Skip to content

Commit 83c9180

Browse files
authored
Merge pull request #91 from tadata-org/feature/authentication
Add Authorization
2 parents bbb7528 + f83581c commit 83c9180

17 files changed

+1593
-102
lines changed

.pre-commit-config.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ repos:
33
rev: v5.0.0
44
hooks:
55
- id: trailing-whitespace
6+
exclude: \.md$
67
- id: check-yaml
78
- id: check-added-large-files
89

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.3.1]
9+
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. (#10)
16+
- 🎉 Support passing http headers to tool calls (#82)
17+
818
## [0.3.0]
919

1020
🚀 FastApiMCP now works with ASGI-transport by default.

README.md

+30-10
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://img.shields.io/pypi/v/fastapi-mcp?color=%2334D058&label=pypi%20package)](https://pypi.org/project/fastapi-mcp/)
@@ -16,11 +16,20 @@
1616

1717
## Features
1818

19-
- **Zero configuration** - Just point it at your FastAPI app and it works, with automatic discovery of endpoints and conversion to MCP tools
20-
- **Schema & docs preservation** - Keep the same request/response models and preserve documentation of all your endpoints
21-
- **Flexible deployment** - Mount your MCP server to the same FastAPI application, or deploy separately
22-
- **Custom endpoint exposure** - Control which endpoints become MCP tools using operation IDs and tags
23-
- **ASGI transport** - Uses FastAPI's ASGI interface directly by default for efficient communication
19+
- **Authentication** built in, using your existing FastAPI dependencies!
20+
21+
- **FastAPI-native:** Not just another OpenAPI -> MCP converter
22+
23+
- **Zero/Minimal configuration** required - just point it at your FastAPI app and it works
24+
25+
- **Preserving schemas** of your request models and response models
26+
27+
- **Preserve documentation** of all your endpoints, just as it is in Swagger
28+
29+
- **Flexible deployment** - Mount your MCP server to the same app, or deploy separately
30+
31+
- **ASGI transport** - Uses FastAPI's ASGI interface directly for efficient communication
32+
2433

2534
## Installation
2635

@@ -52,9 +61,7 @@ mcp = FastApiMCP(app)
5261
mcp.mount()
5362
```
5463

55-
That's it! Your auto-generated MCP server is now available at `https://app.base.url/mcp`.
56-
57-
> **Note on `base_url`**: While `base_url` is optional, it is highly recommended to provide it explicitly. The `base_url` tells the MCP server where to send API requests when tools are called. Without it, the library will attempt to determine the URL automatically, which may not work correctly in deployed environments where the internal and external URLs differ.
64+
That's it! Your auto-generated MCP server is now available at `https://app.base.url/mcp`.
5865

5966
## Documentation, Examples and Advanced Usage
6067

@@ -63,10 +70,23 @@ FastAPI-MCP provides comprehensive documentation in the `docs` folder:
6370
- [FAQ](docs/00_FAQ.md) - Frequently asked questions about usage, development and support
6471
- [Tool Naming](docs/01_tool_naming.md) - Best practices for naming your MCP tools using operation IDs
6572
- [Connecting to MCP Server](docs/02_connecting_to_the_mcp_server.md) - How to connect various MCP clients like Cursor and Claude Desktop
66-
- [Advanced Usage](docs/03_advanced_usage.md) - Advanced features like custom schemas, endpoint filtering, and separate deployment
73+
- [Authentication and Authorization](docs/03_authentication_and_authorization.md) - How to authenticate and authorize your MCP tools
74+
- [Advanced Usage](docs/04_advanced_usage.md) - Advanced features like custom schemas, endpoint filtering, and separate deployment
6775

6876
Check out the [examples directory](examples) for code samples demonstrating these features in action.
6977

78+
## FastAPI-first Approach
79+
80+
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:
81+
82+
- **Native dependencies**: Secure your MCP endpoints using familiar FastAPI `Depends()` for authentication and authorization
83+
84+
- **ASGI transport**: Communicates directly with your FastAPI app using its ASGI interface, eliminating the need for HTTP calls from the MCP to your API
85+
86+
- **Unified infrastructure**: Your FastAPI app doesn't need to run separately from the MCP server (though [separate deployment](docs/04_advanced_usage.md#deploying-separately-from-original-fastapi-app) is also supported)
87+
88+
This design philosophy ensures minimum friction when adding MCP capabilities to your existing FastAPI services.
89+
7090
## Development and Contributing
7191

7292
Thank you for considering contributing to FastAPI-MCP! We encourage the community to post Issues and create Pull Requests.

docs/02_connecting_to_the_mcp_server.md

+16-23
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,35 @@
22

33
## Connecting to the MCP Server using SSE
44

5-
Once your FastAPI app with MCP integration is running, you can connect to it with any MCP client supporting SSE, such as Cursor:
5+
Once your FastAPI app with MCP integration is running, you can connect to it with any MCP client supporting SSE.
66

7-
1. Run your application.
8-
2. In Cursor -> Settings -> MCP, use the URL of your MCP server endpoint (e.g., `http://localhost:8000/mcp`) as sse.
9-
3. Cursor will discover all available tools and resources automatically.
7+
All the most popular MCP clients (Claude Desktop, Cursor & Windsurf) use the following config format:
108

11-
## Connecting to the MCP Server using [mcp-proxy stdio](https://github.com/sparfenyuk/mcp-proxy?tab=readme-ov-file#1-stdio-to-sse)
12-
13-
If your MCP client does not support SSE, for example Claude Desktop:
14-
15-
1. Run your application.
16-
2. Install [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy?tab=readme-ov-file#installing-via-pypi), for example: `uv tool install mcp-proxy`.
17-
3. Add in Claude Desktop MCP config file (`claude_desktop_config.json`):
18-
19-
On Windows:
209
```json
2110
{
2211
"mcpServers": {
23-
"my-api-mcp-proxy": {
24-
"command": "mcp-proxy",
25-
"args": ["http://127.0.0.1:8000/mcp"]
12+
"fastapi-mcp": {
13+
"url": "http://localhost:8000/mcp"
2614
}
2715
}
2816
}
2917
```
30-
On MacOS:
18+
19+
## Connecting to the MCP Server using [mcp-remote](https://www.npmjs.com/package/mcp-remote)
20+
21+
If you want to support authentication, or your MCP client does not support SSE, we recommend using `mcp-remote` as a bridge.
22+
3123
```json
3224
{
3325
"mcpServers": {
34-
"my-api-mcp-proxy": {
35-
"command": "/Full/Path/To/Your/Executable/mcp-proxy",
36-
"args": ["http://127.0.0.1:8000/mcp"]
26+
"fastapi-mcp": {
27+
"command": "npx",
28+
"args": [
29+
"mcp-remote",
30+
"http://localhost:8000/mcp",
31+
"8080" // Optional port number. Necessary if you want your OAuth to work and you don't have dynamic client registration.
32+
]
3733
}
3834
}
3935
}
4036
```
41-
Find the path to mcp-proxy by running in Terminal: `which mcp-proxy`.
42-
43-
4. Claude Desktop will discover all available tools and resources automatically.
+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Authentication and Authorization
2+
3+
FastAPI-MCP supports authentication and authorization using your existing FastAPI dependencies.
4+
5+
It also supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).
6+
7+
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.
8+
9+
## Basic Token Passthrough
10+
11+
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.
12+
13+
You just need to make sure your MCP client is sending it:
14+
15+
```json
16+
{
17+
"mcpServers": {
18+
"remote-example": {
19+
"command": "npx",
20+
"args": [
21+
"mcp-remote",
22+
"http://localhost:8000/mcp",
23+
"--header",
24+
"Authorization:${AUTH_HEADER}"
25+
]
26+
},
27+
"env": {
28+
"AUTH_HEADER": "Bearer <your-token>"
29+
}
30+
}
31+
}
32+
```
33+
34+
This is enough to pass the authorization header to your FastAPI endpoints.
35+
36+
Optionally, if you want your MCP server to reject requests without an authorization header, you can add a dependency:
37+
38+
```python
39+
from fastapi import Depends
40+
from fastapi_mcp import FastApiMCP, AuthConfig
41+
42+
mcp = FastApiMCP(
43+
app,
44+
name="Protected MCP",
45+
auth_config=AuthConfig(
46+
dependencies=[Depends(verify_auth)],
47+
),
48+
)
49+
mcp.mount()
50+
```
51+
52+
## OAuth Flow
53+
54+
FastAPI-MCP supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).
55+
56+
It would look something like this:
57+
58+
```python
59+
from fastapi import Depends
60+
from fastapi_mcp import FastApiMCP, AuthConfig
61+
62+
mcp = FastApiMCP(
63+
app,
64+
name="MCP With OAuth",
65+
auth_config=AuthConfig(
66+
issuer=f"https://auth.example.com/",
67+
authorize_url=f"https://auth.example.com/authorize",
68+
oauth_metadata_url=f"https://auth.example.com/.well-known/oauth-authorization-server",
69+
audience="my-audience",
70+
client_id="my-client-id",
71+
client_secret="my-client-secret",
72+
dependencies=[Depends(verify_auth)],
73+
setup_proxies=True,
74+
),
75+
)
76+
77+
mcp.mount()
78+
```
79+
80+
And you can call it like:
81+
82+
```json
83+
{
84+
"mcpServers": {
85+
"fastapi-mcp": {
86+
"command": "npx",
87+
"args": [
88+
"mcp-remote",
89+
"http://localhost:8000/mcp",
90+
"8080" // Optional port number. Necessary if you want your OAuth to work and you don't have dynamic client registration.
91+
]
92+
}
93+
}
94+
}
95+
```
96+
97+
You can use it with any OAuth provider that supports the OAuth 2 spec. See explanation on [AuthConfig](#authconfig-explained) for more details.
98+
99+
## Custom OAuth Metadata
100+
101+
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:
102+
103+
```python
104+
from fastapi import Depends
105+
from fastapi_mcp import FastApiMCP, AuthConfig
106+
107+
mcp = FastApiMCP(
108+
app,
109+
name="MCP With Custom OAuth",
110+
auth_config=AuthConfig(
111+
# Provide your own complete OAuth metadata
112+
custom_oauth_metadata={
113+
"issuer": "https://auth.example.com",
114+
"authorization_endpoint": "https://auth.example.com/authorize",
115+
"token_endpoint": "https://auth.example.com/token",
116+
"registration_endpoint": "https://auth.example.com/register",
117+
"scopes_supported": ["openid", "profile", "email"],
118+
"response_types_supported": ["code"],
119+
"grant_types_supported": ["authorization_code"],
120+
"token_endpoint_auth_methods_supported": ["none"],
121+
"code_challenge_methods_supported": ["S256"]
122+
},
123+
124+
# Your auth checking dependency
125+
dependencies=[Depends(verify_auth)],
126+
),
127+
)
128+
129+
mcp.mount()
130+
```
131+
132+
This approach gives you complete control over the OAuth metadata and is useful when:
133+
- You have a fully MCP-compliant OAuth server already configured
134+
- You need to customize the OAuth flow beyond what the proxy approach offers
135+
- You're using a custom or specialized OAuth implementation
136+
137+
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.
138+
139+
## Working Example with Auth0
140+
141+
For a complete working example of OAuth integration with Auth0, check out the [auth_example_auth0.py](/examples/08_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.
142+
143+
For it to work, you need an .env file in the root of the project with the following variables:
144+
145+
```
146+
AUTH0_DOMAIN=your-tenant.auth0.com
147+
AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/
148+
AUTH0_CLIENT_ID=your-client-id
149+
AUTH0_CLIENT_SECRET=your-client-secret
150+
```
151+
152+
You also need to make sure to configure callback URLs properly in your Auth0 dashboard.
153+
154+
## AuthConfig Explained
155+
156+
### `setup_proxies=True`
157+
158+
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:
159+
160+
```python
161+
mcp = FastApiMCP(
162+
app,
163+
auth_config=AuthConfig(
164+
# Your OAuth provider information
165+
issuer="https://auth.example.com",
166+
authorize_url="https://auth.example.com/authorize",
167+
oauth_metadata_url="https://auth.example.com/.well-known/oauth-authorization-server",
168+
169+
# Credentials registered with your OAuth provider
170+
client_id="your-client-id",
171+
client_secret="your-client-secret",
172+
173+
# Recommended, since some clients don't specify them
174+
audience="your-api-audience",
175+
default_scope="openid profile email",
176+
177+
# Your auth checking dependency
178+
dependencies=[Depends(verify_auth)],
179+
180+
# Create compatibility proxies - usually needed!
181+
setup_proxies=True,
182+
),
183+
)
184+
```
185+
186+
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).
187+
188+
### Why Use Proxies?
189+
190+
Proxies solve several problems:
191+
192+
1. **Missing registration endpoints**:
193+
The MCP spec expects OAuth providers to support [dynamic client registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591), but many don't.
194+
Furthermore, dynamic client registration is probably overkill for most use cases.
195+
The `setup_fake_dynamic_registration` option (True by default) creates a compatible endpoint that just returns a static client ID and secret.
196+
197+
2. **Scope handling**:
198+
Some MCP clients don't properly request scopes, so our proxy adds the necessary scopes for you.
199+
200+
3. **Audience requirements**:
201+
Some OAuth providers require an audience parameter that MCP clients don't always provide. The proxy adds this automatically.
202+
203+
### Add a fixed port to mcp-remote
204+
205+
```json
206+
{
207+
"mcpServers": {
208+
"example": {
209+
"command": "npx",
210+
"args": [
211+
"mcp-remote",
212+
"http://localhost:8000/mcp",
213+
"8080"
214+
]
215+
}
216+
}
217+
}
218+
```
219+
220+
Normally, mcp-remote will start on a random port, making it impossible to configure the OAuth provider's callback URL properly.
221+
222+
223+
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.

0 commit comments

Comments
 (0)