|
1 | 1 | <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>
|
2 | 2 | <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> |
4 | 4 | <div align="center">
|
5 | 5 |
|
6 | 6 | [](https://pypi.org/project/fastapi-mcp/)
|
|
17 | 17 |
|
18 | 18 | ## Features
|
19 | 19 |
|
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 | + |
23 | 26 | - **Preserving schemas** of your request models and response models
|
| 27 | + |
24 | 28 | - **Preserve documentation** of all your endpoints, just as it is in Swagger
|
| 29 | + |
25 | 30 | - **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 | + |
27 | 34 |
|
28 | 35 | ## Installation
|
29 | 36 |
|
@@ -57,6 +64,225 @@ mcp.mount()
|
57 | 64 |
|
58 | 65 | That's it! Your auto-generated MCP server is now available at `https://app.base.url/mcp`.
|
59 | 66 |
|
| 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 | + |
60 | 286 | ## Tool Naming
|
61 | 287 |
|
62 | 288 | 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
|
246 | 472 |
|
247 | 473 | 3. Cursor will discover all available tools and resources automatically.
|
248 | 474 |
|
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) |
250 | 476 |
|
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. |
252 | 478 |
|
253 |
| -1. Run your application. |
| 479 | +All the most popular MCP clients (Claude Desktop, Cursor & Windsurf) use the following config format: |
254 | 480 |
|
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: |
271 | 481 | ```json
|
272 | 482 | {
|
273 | 483 | "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 | + ] |
277 | 491 | }
|
278 | 492 | }
|
279 | 493 | }
|
280 | 494 | ```
|
281 |
| -Find the path to mcp-proxy by running in Terminal: `which mcp-proxy`. |
282 | 495 |
|
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. |
284 | 507 |
|
285 | 508 | ## Development and Contributing
|
286 | 509 |
|
|
0 commit comments