Skip to content

Commit 5da6fed

Browse files
committed
Add Authorization
1 parent f9490d6 commit 5da6fed

File tree

11 files changed

+1415
-90
lines changed

11 files changed

+1415
-90
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
🚀 FastApiMCP now supports MCP Authorization!
11+
12+
You can now add MCP-compliant OAuth configuration in a FastAPI-native way, using your existing FastAPI `Depends()` that we all know and love.
13+
14+
### Added
15+
- 🎉 Support for Authentication / Authorization compliant to [MCP 2025-03-26 Specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization), using OAuth 2.1
16+
17+
## [Unreleased]
18+
1019
🚀 FastApiMCP now works with ASGI-transport by default.
1120

1221
This means the `base_url` argument is redundant, and thus has been removed.

README.md

Lines changed: 252 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<p align="center"><a href="https://github.com/tadata-org/fastapi_mcp"><img src="https://github.com/user-attachments/assets/7e44e98b-a0ba-4aff-a68a-4ffee3a6189c" alt="fastapi-to-mcp" height=100/></a></p>
22
<h1 align="center">FastAPI-MCP</h1>
3-
<p align="center">A zero-configuration tool for automatically exposing FastAPI endpoints as Model Context Protocol (MCP) tools.</p>
3+
<p align="center">Expose your FastAPI endpoints as Model Context Protocol (MCP) tools, with Auth!</p>
44
<div align="center">
55

66
[![PyPI version](https://badge.fury.io/py/fastapi-mcp.svg)](https://pypi.org/project/fastapi-mcp/)
@@ -17,13 +17,20 @@
1717

1818
## Features
1919

20-
- **Direct integration** - Mount an MCP server directly to your FastAPI app
21-
- **Zero configuration** required - just point it at your FastAPI app and it works
22-
- **Automatic discovery** of all FastAPI endpoints and conversion to MCP tools
20+
- **FastAPI-native:** Not just another OpenAPI -> MCP converter
21+
22+
- **Authentication** built in, using your existing FastAPI dependencies!
23+
24+
- **Zero/Minimal configuration** required - just point it at your FastAPI app and it works
25+
2326
- **Preserving schemas** of your request models and response models
27+
2428
- **Preserve documentation** of all your endpoints, just as it is in Swagger
29+
2530
- **Flexible deployment** - Mount your MCP server to the same app, or deploy separately
26-
- **ASGI transport** - Uses FastAPI's ASGI interface directly by default for efficient communication
31+
32+
- **ASGI transport** - Uses FastAPI's ASGI interface directly for efficient communication
33+
2734

2835
## Installation
2936

@@ -57,6 +64,225 @@ mcp.mount()
5764

5865
That's it! Your auto-generated MCP server is now available at `https://app.base.url/mcp`.
5966

67+
# Authentication and Authorization
68+
69+
FastAPI-MCP supports authentication and authorization using your existing FastAPI dependencies.
70+
71+
It also supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).
72+
73+
It's worth noting that most MCP clients currently do not support the latest MCP spec, so for our examples we might use a bridge client such as `npx mcp-remote`. We recommend you use it as well, and we'll show our examples using it.
74+
75+
## Basic Token Passthrough
76+
77+
If you just want to be able to pass a valid authorization header, without supporting a full authentication flow, you don't need to do anything special.
78+
79+
You just need to make sure your MCP client is sending it:
80+
81+
```json
82+
{
83+
"mcpServers": {
84+
"remote-example": {
85+
"command": "npx",
86+
"args": [
87+
"mcp-remote",
88+
"http://localhost:8000/mcp",
89+
"--header",
90+
"Authorization:${AUTH_HEADER}"
91+
]
92+
},
93+
"env": {
94+
"AUTH_HEADER": "Bearer <your-token>"
95+
}
96+
}
97+
}
98+
```
99+
100+
This is enough to pass the authorization header to your FastAPI endpoints.
101+
102+
Optionally, if you want your MCP server to reject requests without an authorization header, you can add a dependency:
103+
104+
```python
105+
from fastapi import Depends
106+
from fastapi_mcp import FastApiMCP, AuthConfig
107+
108+
mcp = FastApiMCP(
109+
app,
110+
name="Protected MCP",
111+
auth_config=AuthConfig(
112+
dependencies=[Depends(verify_auth)],
113+
),
114+
)
115+
mcp.mount()
116+
```
117+
118+
## OAuth Flow
119+
120+
FastAPI-MCP supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).
121+
122+
It would look something like this:
123+
124+
```python
125+
from fastapi import Depends
126+
from fastapi_mcp import FastApiMCP, AuthConfig
127+
128+
mcp = FastApiMCP(
129+
app,
130+
name="MCP With OAuth",
131+
auth_config=AuthConfig(
132+
issuer=f"https://auth.example.com/",
133+
authorize_url=f"https://auth.example.com/authorize",
134+
oauth_metadata_url=f"https://auth.example.com/.well-known/oauth-authorization-server",
135+
audience="my-audience",
136+
client_id="my-client-id",
137+
client_secret="my-client-secret",
138+
dependencies=[Depends(verify_auth)],
139+
setup_proxies=True,
140+
),
141+
)
142+
143+
mcp.mount()
144+
```
145+
146+
And you can call it like:
147+
148+
```json
149+
{
150+
"mcpServers": {
151+
"fastapi-mcp": {
152+
"command": "npx",
153+
"args": [
154+
"mcp-remote",
155+
"http://localhost:8000/mcp",
156+
"8080" // Optional port number. Necessary if you want your OAuth to work and you don't have dynamic client registration.
157+
]
158+
}
159+
}
160+
}
161+
```
162+
163+
You can use it with any OAuth provider that supports the OAuth 2 spec. See explanation on [AuthConfig](#authconfig-explained) for more details.
164+
165+
## Custom OAuth Metadata
166+
167+
If you already have a properly configured OAuth server that works with MCP clients, or if you want full control over the metadata, you can provide your own OAuth metadata directly:
168+
169+
```python
170+
from fastapi import Depends
171+
from fastapi_mcp import FastApiMCP, AuthConfig
172+
173+
mcp = FastApiMCP(
174+
app,
175+
name="MCP With Custom OAuth",
176+
auth_config=AuthConfig(
177+
# Provide your own complete OAuth metadata
178+
custom_oauth_metadata={
179+
"issuer": "https://auth.example.com",
180+
"authorization_endpoint": "https://auth.example.com/authorize",
181+
"token_endpoint": "https://auth.example.com/token",
182+
"registration_endpoint": "https://auth.example.com/register",
183+
"scopes_supported": ["openid", "profile", "email"],
184+
"response_types_supported": ["code"],
185+
"grant_types_supported": ["authorization_code"],
186+
"token_endpoint_auth_methods_supported": ["none"],
187+
"code_challenge_methods_supported": ["S256"]
188+
},
189+
190+
# Your auth checking dependency
191+
dependencies=[Depends(verify_auth)],
192+
),
193+
)
194+
195+
mcp.mount()
196+
```
197+
198+
This approach gives you complete control over the OAuth metadata and is useful when:
199+
- You have a fully MCP-compliant OAuth server already configured
200+
- You need to customize the OAuth flow beyond what the proxy approach offers
201+
- You're using a custom or specialized OAuth implementation
202+
203+
For this to work, you have to make sure mcp-remote is running [on a fixed port](#add-a-fixed-port-to-mcp-remote), for example `8080`, and then configure the callback URL to `http://127.0.0.1:8080/oauth/callback` in your OAuth provider.
204+
205+
## Working Example with Auth0
206+
207+
For a complete working example of OAuth integration with Auth0, check out the [auth_example_auth0.py](examples/auth_example_auth0.py) in the examples folder. This example demonstrates the simple case of using Auth0 as an OAuth provider, with a working example of the OAuth flow.
208+
209+
For it to work, you need an .env file in the root of the project with the following variables:
210+
211+
```
212+
AUTH0_DOMAIN=your-tenant.auth0.com
213+
AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/
214+
AUTH0_CLIENT_ID=your-client-id
215+
AUTH0_CLIENT_SECRET=your-client-secret
216+
```
217+
218+
You also need to make sure to configure callback URLs properly in your Auth0 dashboard.
219+
220+
## AuthConfig Explained
221+
222+
### `setup_proxies=True`
223+
224+
Most OAuth providers need some adaptation to work with MCP clients. This is where `setup_proxies=True` comes in - it creates proxy endpoints that make your OAuth provider compatible with MCP clients:
225+
226+
```python
227+
mcp = FastApiMCP(
228+
app,
229+
auth_config=AuthConfig(
230+
# Your OAuth provider information
231+
issuer="https://auth.example.com",
232+
authorize_url="https://auth.example.com/authorize",
233+
oauth_metadata_url="https://auth.example.com/.well-known/oauth-authorization-server",
234+
235+
# Credentials registered with your OAuth provider
236+
client_id="your-client-id",
237+
client_secret="your-client-secret",
238+
239+
# Recommended, since some clients don't specify them
240+
audience="your-api-audience",
241+
default_scope="openid profile email",
242+
243+
# Your auth checking dependency
244+
dependencies=[Depends(verify_auth)],
245+
246+
# Create compatibility proxies - usually needed!
247+
setup_proxies=True,
248+
),
249+
)
250+
```
251+
252+
You also need to make sure to configure callback URLs properly in your OAuth provider. With mcp-remote for example, you have to [use a fixed port](#add-a-fixed-port-to-mcp-remote).
253+
254+
### Why Use Proxies?
255+
256+
Proxies solve several problems:
257+
258+
1. **Missing registration endpoints**: The MCP spec expects OAuth providers to support dynamic client registration, but many don't. The `setup_fake_dynamic_registration=True` option creates a compatible endpoint that just returns a static client ID and secret.
259+
260+
2. **Scope handling**: Some MCP clients don't properly request scopes, so our proxy adds the necessary scopes for you.
261+
262+
3. **Audience requirements**: Some OAuth providers require an audience parameter that MCP clients don't always provide. The proxy adds this automatically.
263+
264+
### Add a fixed port to mcp-remote
265+
266+
```json
267+
{
268+
"mcpServers": {
269+
"example": {
270+
"command": "npx",
271+
"args": [
272+
"mcp-remote",
273+
"http://localhost:8000/mcp",
274+
"8080"
275+
]
276+
}
277+
}
278+
}
279+
```
280+
281+
Normally, mcp-remote will start on a random port, making it impossible to configure the OAuth provider's callback URL properly.
282+
283+
284+
You have to make sure mcp-remote is running on a fixed port, for example `8080`, and then configure the callback URL to `http://127.0.0.1:8080/oauth/callback` in your OAuth provider.
285+
60286
## Tool Naming
61287

62288
FastAPI-MCP uses the `operation_id` from your FastAPI routes as the MCP tool names. When you don't specify an `operation_id`, FastAPI auto-generates one, but these can be cryptic.
@@ -246,41 +472,38 @@ Once your FastAPI app with MCP integration is running, you can connect to it wit
246472

247473
3. Cursor will discover all available tools and resources automatically.
248474

249-
## Connecting to the MCP Server using [mcp-proxy stdio](https://github.com/sparfenyuk/mcp-proxy?tab=readme-ov-file#1-stdio-to-sse)
475+
## Connecting to the MCP Server using [mcp-remote](https://www.npmjs.com/package/mcp-remote)
250476

251-
If your MCP client does not support SSE, for example Claude Desktop:
477+
If your MCP client does not support SSE, or, if you want want to support authentication, we recommend using `mcp-remote` as a bridge.
252478

253-
1. Run your application.
479+
All the most popular MCP clients (Claude Desktop, Cursor & Windsurf) use the following config format:
254480

255-
2. Install [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy?tab=readme-ov-file#installing-via-pypi), for example: `uv tool install mcp-proxy`.
256-
257-
3. Add in Claude Desktop MCP config file (`claude_desktop_config.json`):
258-
259-
On Windows:
260-
```json
261-
{
262-
"mcpServers": {
263-
"my-api-mcp-proxy": {
264-
"command": "mcp-proxy",
265-
"args": ["http://127.0.0.1:8000/mcp"]
266-
}
267-
}
268-
}
269-
```
270-
On MacOS:
271481
```json
272482
{
273483
"mcpServers": {
274-
"my-api-mcp-proxy": {
275-
"command": "/Full/Path/To/Your/Executable/mcp-proxy",
276-
"args": ["http://127.0.0.1:8000/mcp"]
484+
"fastapi-mcp": {
485+
"command": "npx",
486+
"args": [
487+
"mcp-remote",
488+
"http://localhost:8000/mcp",
489+
"8080" // Optional port number. Necessary if you want your OAuth to work and you don't have dynamic client registration.
490+
]
277491
}
278492
}
279493
}
280494
```
281-
Find the path to mcp-proxy by running in Terminal: `which mcp-proxy`.
282495

283-
4. Claude Desktop will discover all available tools and resources automatically
496+
## FastAPI-first Approach
497+
498+
FastAPI-MCP is designed as a native extension of FastAPI, not just a converter that generates MCP tools from your API. This approach offers several key advantages:
499+
500+
- **Native dependencies**: Secure your MCP endpoints using familiar FastAPI `Depends()` for authentication and authorization
501+
502+
- **ASGI transport**: Communicates directly with your FastAPI app using its ASGI interface, eliminating the need for HTTP calls from the MCP to your API
503+
504+
- **Unified infrastructure**: Your FastAPI app doesn't need to run separately from the MCP server (though [separate deployment](#deploying-separately-from-original-fastapi-app) is also supported)
505+
506+
This design philosophy ensures minimum friction when adding MCP capabilities to your existing FastAPI services.
284507

285508
## Development and Contributing
286509

0 commit comments

Comments
 (0)