diff --git a/daprdocs/content/en/developing-applications/mcp/_index.md b/daprdocs/content/en/developing-applications/mcp/_index.md new file mode 100644 index 00000000000..8ec13454224 --- /dev/null +++ b/daprdocs/content/en/developing-applications/mcp/_index.md @@ -0,0 +1,12 @@ +--- +type: docs +title: "MCP" +linkTitle: "MCP" +weight: 25 +description: "Dapr helps developers run secure and reliable MCP servers" +--- + +### What does Dapr do for MCP servers? + +Using Dapr, developers can interact securely with MCP servers and enable fine-grained ACLs with built-in tracing and metrics, as well as resiliency policies to handle situations where an MCP server might be down or unresponsive. + \ No newline at end of file diff --git a/daprdocs/content/en/developing-applications/mcp/mcp-authentication.md b/daprdocs/content/en/developing-applications/mcp/mcp-authentication.md new file mode 100644 index 00000000000..518e09909a6 --- /dev/null +++ b/daprdocs/content/en/developing-applications/mcp/mcp-authentication.md @@ -0,0 +1,197 @@ +--- +type: docs +title: "Authenticating an MCP server" +linkTitle: "Getting Started" +weight: 20 +description: "How to enable MCP client-side and server-side authentication" +--- + +## Overview + +The MCP specification does not mandate any form of authentication between an MCP client and server. The security model is left to the user to plan and implement, which creates a maintanance burden on developers and opens up MCP servers to various attack surfaces. + +While MCP servers lack identity, OAuth2 is a well established standard that can be used to properly authenticate MCP clients to MCP servers. + +OAuth2 becomes essential when MCP servers are: + +* Multi-tenant +* Remote +* Cloud-hosted +* Connected to confidential systems +* Performing privileged actions on behalf of a user +* Exposing tools that must be permission-gated + +Dapr enables seamless OAuth2 authentication between MCP clients and servers using [middleware]({{% ref "middleware" %}}) components. + +## Types of authentication + +Dapr supports two critical authentication mechanisms for production grade deployments of MCP servers - Client-side and Server-side. + +### Client-side Authentication + +The client initiates OAuth2 to obtain an access token and includes it when connecting to the MCP server. +This proves the user’s identity and permissions and is required for remote, sensitive, or multi-tenant MCP servers. +It ensures the server can trust who is calling and what scopes the client is allowed to use. + +### Server-side Authentication + +The server validates the client’s token or, if missing or insufficient, triggers an OAuth2 login or scope upgrade. +This is needed for cloud-hosted or shared MCP servers, tenant-aware systems, and integrations that require user-specific authorization. +It enforces access control, isolates users, and protects privileged tools and data. + +## How to enable Client-side Authentication + +### Define the MCP Server as an HTTPEndpoint + +Dapr allows developers and operators to model remote HTTP services as resources that can be governed and invoked using the Dapr [Service Invocation API]({{% ref "service-invocation-overview" %}}). + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: HTTPEndpoint +metadata: + name: "mcp-server" +spec: + baseUrl: https://my-mcp-server:443 + headers: + - name: "Accept" + value: "text/event-stream" +``` + +### Define the OAuth2 middleware and configuration components + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: oauth2 +spec: + type: middleware.http.oauth2 + version: v1 + metadata: + - name: clientId + value: "" + - name: clientSecret + value: "" + - name: authURL + value: "" + - name: tokenURL + value: "" + - name: scopes + value: "" +``` + +Next, create the configuration component. + +```yaml +piVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: auth +spec: + tracing: + samplingRate: "1" + httpPipeline: + handlers: + - name: oauth2 # reference the oauth component here + type: middleware.http.oauth2 +``` + +*Note: visit [this link]({{% ref "component-secrets.md" %}}) to read on how to provide secrets to Dapr components* + +### Call the MCP server using an MCP client + +```python +import asyncio +from mcp import ClientSession +from mcp.transport.http import HttpClientTransport + +async def main(): + # Address of the Dapr process + server_url = "http://localhost:3500/" + + # Create an HTTP/SSE transport with a header to target our HTTPEndpoint defined above + transport = HttpClientTransport( + url=server_url, + headers={ + "dapr-app-id": "mcp-server", + } + event_headers={ + "Accept": "text/event-stream", + }, + ) + + # Create an MCP session bound to the transport + async with ClientSession(transport) as session: + await session.initialize() + + tools = await session.call("tools/list") + print("Server Tools:", tools)) + + await session.shutdown() + +if __name__ == "__main__": + asyncio.run(main()) +``` + +### Run the MCP client with Dapr + +Put the YAML files above in `components` directory and run Dapr: + +```bash +dapr run --app-id mcpclient --resources-path ./components --dapr-http-port 3500 --config ./config.yaml -- python mcpclient.py +``` + +If properly configured, the MCP client will cause Dapr to kick off an OAuth2 pipeline before connecting to the MCP server. + +## How to enable Server-side Authentication + +### Define the OAuth2 middleware and configuration components + +We define a middleware component the same as above. + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: oauth2 +spec: + type: middleware.http.oauth2 + version: v1 + metadata: + - name: clientId + value: "" + - name: clientSecret + value: "" + - name: authURL + value: "" + - name: tokenURL + value: "" + - name: scopes + value: "" +``` + +Next, create the configuration component, with the modification of an `appHttpPipeline` field. This tells Dapr to apply the middleware for incoming calls. + +```yaml +piVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: auth +spec: + tracing: + samplingRate: "1" + appHttpPipeline: + handlers: + - name: oauth2 # reference the oauth component here + type: middleware.http.oauth2 +``` + +### Run the MCP server with Dapr + +Put the YAML files above in `components` directory and run Dapr: + +```bash +dapr run --app-id mcpclient --resources-path ./components --dapr-http-port 3500 --config ./config.yaml -- python mcpserver.py +``` + +If properly configured, Dapr will kick off an OAuth2 pipeline when a request for the MCP server arrives.