Skip to content

Commit fbee78b

Browse files
authored
Merge pull request #4972 from dapr/mcp-1
Add mcp auth documentation
2 parents a203d79 + db14ed6 commit fbee78b

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
type: docs
3+
title: "MCP"
4+
linkTitle: "MCP"
5+
weight: 25
6+
description: "Dapr helps developers run secure and reliable Model Context Protocol (MCP) servers"
7+
---
8+
9+
### What does Dapr do for MCP servers?
10+
11+
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.
12+
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
---
2+
type: docs
3+
title: "Authenticating an MCP server"
4+
linkTitle: "Getting Started"
5+
weight: 20
6+
description: "How to enable MCP client-side and server-side authentication"
7+
---
8+
9+
## Overview
10+
11+
The [MCP specification](https://modelcontextprotocol.io/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. This creates a maintenance burden on developers and opens up MCP servers to various attack surfaces.
12+
13+
While MCP servers lack identity, OAuth2 is a well established standard that can be used to properly authenticate MCP clients to MCP servers.
14+
15+
OAuth2 becomes essential when MCP servers are:
16+
17+
* Multi-tenant
18+
* Remote
19+
* Cloud-hosted
20+
* Connected to confidential systems
21+
* Performing privileged actions on behalf of a user
22+
* Exposing tools that must be permission-gated
23+
24+
Dapr enables OAuth2 authentication between MCP clients and servers using [middleware]({{% ref "middleware" %}}) components.
25+
26+
## Types of authentication
27+
28+
Dapr supports two critical authentication mechanisms for production grade deployments of MCP servers - Client-side and Server-side.
29+
30+
### Client-side Authentication
31+
32+
The client initiates OAuth2 to obtain an access token and includes it when connecting to the MCP server.
33+
This proves the user’s identity and permissions and is required for remote, sensitive, or multi-tenant MCP servers.
34+
It ensures the server can trust who is calling and what scopes the client is allowed to use.
35+
36+
### Server-side Authentication
37+
38+
The server validates the client’s token or, if missing or insufficient, triggers an OAuth2 login or scope upgrade.
39+
This is needed for cloud-hosted or shared MCP servers, tenant-aware systems, and integrations that require user-specific authorization.
40+
It enforces access control, isolates users, and protects privileged tools and data.
41+
42+
## How to enable Client-side Authentication
43+
44+
### Define the MCP Server as an HTTPEndpoint
45+
46+
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" %}}).
47+
Create this `HTTPEndpoint` resource to represent the MCP server:
48+
49+
```yaml
50+
apiVersion: dapr.io/v1alpha1
51+
kind: HTTPEndpoint
52+
metadata:
53+
name: "mcp-server"
54+
spec:
55+
baseUrl: https://my-mcp-server:443
56+
headers:
57+
- name: "Accept"
58+
value: "text/event-stream"
59+
```
60+
61+
### Define the OAuth2 middleware and configuration components
62+
63+
The following middleware component defines the connection to the OAuth2 provider:
64+
65+
```yaml
66+
apiVersion: dapr.io/v1alpha1
67+
kind: Component
68+
metadata:
69+
name: oauth2
70+
spec:
71+
type: middleware.http.oauth2
72+
version: v1
73+
metadata:
74+
- name: clientId
75+
value: "<client-id>"
76+
- name: clientSecret
77+
value: "<client-secret>"
78+
- name: authURL
79+
value: "<authorization-url>"
80+
- name: tokenURL
81+
value: "<token-url>"
82+
- name: scopes
83+
value: "<comma-separated scopes>"
84+
```
85+
86+
Next, create the configuration resource which tells Dapr to use the OAuth2 middleware:
87+
88+
```yaml
89+
piVersion: dapr.io/v1alpha1
90+
kind: Configuration
91+
metadata:
92+
name: auth
93+
spec:
94+
tracing:
95+
samplingRate: "1"
96+
httpPipeline:
97+
handlers:
98+
- name: oauth2 # reference the oauth component here
99+
type: middleware.http.oauth2
100+
```
101+
102+
{{% alert title="Note" color="primary" %}}
103+
Visit [this link]({{% ref "component-secrets.md" %}}) to read on how to provide secrets to Dapr components
104+
{{% /alert %}}
105+
106+
### Call the MCP server using an MCP client
107+
108+
Copy the following code to a file named `mcpclient.py`:
109+
110+
```python
111+
import asyncio
112+
from mcp import ClientSession
113+
from mcp.transport.http import HttpClientTransport
114+
115+
async def main():
116+
# Default address of the Dapr process. Use an environment variable in production
117+
server_url = "http://localhost:3500/"
118+
119+
# Create an HTTP/SSE transport with a header to target our HTTPEndpoint defined above
120+
transport = HttpClientTransport(
121+
url=server_url,
122+
headers={
123+
"dapr-app-id": "mcp-server",
124+
}
125+
event_headers={
126+
"Accept": "text/event-stream",
127+
},
128+
)
129+
130+
# Create an MCP session bound to the transport
131+
async with ClientSession(transport) as session:
132+
await session.initialize()
133+
134+
tools = await session.call("tools/list")
135+
print("Server Tools:", tools))
136+
137+
await session.shutdown()
138+
139+
if __name__ == "__main__":
140+
asyncio.run(main())
141+
```
142+
143+
### Run the MCP client with Dapr
144+
145+
Put the YAML files above into a `components` directory and run Dapr:
146+
147+
```bash
148+
dapr run --app-id mcpclient --resources-path ./components --dapr-http-port 3500 --config ./config.yaml -- python mcpclient.py
149+
```
150+
151+
The MCP client causes Dapr to start an OAuth2 pipeline before connecting to the MCP server.
152+
153+
## How to enable Server-side Authentication
154+
155+
### Define the OAuth2 middleware and configuration components
156+
157+
Define a middleware component the same as the client example.
158+
159+
```yaml
160+
apiVersion: dapr.io/v1alpha1
161+
kind: Component
162+
metadata:
163+
name: oauth2
164+
spec:
165+
type: middleware.http.oauth2
166+
version: v1
167+
metadata:
168+
- name: clientId
169+
value: "<client-id>"
170+
- name: clientSecret
171+
value: "<client-secret>"
172+
- name: authURL
173+
value: "<authorization-url>"
174+
- name: tokenURL
175+
value: "<token-url>"
176+
- name: scopes
177+
value: "<comma-separated scopes>"
178+
```
179+
180+
Next, create the configuration component, with the modification of an `appHttpPipeline` field. This tells Dapr to apply the middleware for incoming calls.
181+
182+
```yaml
183+
piVersion: dapr.io/v1alpha1
184+
kind: Configuration
185+
metadata:
186+
name: auth
187+
spec:
188+
tracing:
189+
samplingRate: "1"
190+
appHttpPipeline:
191+
handlers:
192+
- name: oauth2 # reference the oauth component here
193+
type: middleware.http.oauth2
194+
```
195+
196+
### Run the MCP server with Dapr
197+
198+
Put the YAML files above in `components` directory and run Dapr:
199+
200+
```bash
201+
dapr run --app-id mcpclient --resources-path ./components --dapr-http-port 3500 --config ./config.yaml -- python mcpserver.py
202+
```
203+
204+
Dapr will start an OAuth2 pipeline when a request for the MCP server arrives.

0 commit comments

Comments
 (0)