Spaces:
Running
Running
Merge pull request #1103 from jlowin/docs
Browse files- .gitignore +3 -0
- docs/clients/transports.mdx +169 -308
- docs/docs.json +18 -14
- docs/integrations/fastapi.mdx +229 -0
- docs/{servers → integrations}/openapi.mdx +88 -190
- docs/{deployment/asgi.mdx → integrations/starlette.mdx} +79 -86
- docs/servers/server.mdx +25 -3
.gitignore
CHANGED
|
@@ -60,3 +60,6 @@ dmypy.json
|
|
| 60 |
*.sqlite
|
| 61 |
*.db
|
| 62 |
*.ddb
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
*.sqlite
|
| 61 |
*.db
|
| 62 |
*.ddb
|
| 63 |
+
|
| 64 |
+
# Claude worktree management
|
| 65 |
+
.claude-wt/worktrees
|
docs/clients/transports.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
---
|
| 2 |
title: Client Transports
|
| 3 |
sidebarTitle: Transports
|
| 4 |
-
description:
|
| 5 |
icon: link
|
| 6 |
---
|
| 7 |
|
|
@@ -9,441 +9,302 @@ import { VersionBadge } from "/snippets/version-badge.mdx"
|
|
| 9 |
|
| 10 |
<VersionBadge version="2.0.0" />
|
| 11 |
|
| 12 |
-
The FastMCP `Client`
|
| 13 |
|
| 14 |
-
|
| 15 |
|
| 16 |
-
|
| 17 |
-
Clients are lightweight objects, so don't hesitate to create new ones as needed. However, be mindful of the context management - each time you open a client context (`async with client:`), a new connection or process starts. For best performance, keep client contexts open while performing multiple operations rather than repeatedly opening and closing them.
|
| 18 |
-
</Tip>
|
| 19 |
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
|
| 23 |
|
| 24 |
-
|
| 25 |
|
| 26 |
-
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
These transports connect to servers running over a network, typically long-running services accessible via URLs.
|
| 33 |
-
|
| 34 |
-
### Streamable HTTP
|
| 35 |
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
|
| 40 |
-
###
|
| 41 |
|
| 42 |
-
|
| 43 |
-
- **Inferred From:** URLs starting with `http://` or `https://` (default for HTTP URLs since v2.3.0) that do not contain `/sse/` in the path
|
| 44 |
-
- **Server Compatibility:** Works with FastMCP servers running in `http` mode
|
| 45 |
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
| 49 |
|
| 50 |
```python
|
| 51 |
from fastmcp import Client
|
| 52 |
-
import asyncio
|
| 53 |
-
|
| 54 |
-
# The Client automatically uses StreamableHttpTransport for HTTP URLs
|
| 55 |
-
client = Client("https://example.com/mcp")
|
| 56 |
-
|
| 57 |
-
async def main():
|
| 58 |
-
async with client:
|
| 59 |
-
tools = await client.list_tools()
|
| 60 |
-
print(f"Available tools: {tools}")
|
| 61 |
-
|
| 62 |
-
asyncio.run(main())
|
| 63 |
-
```
|
| 64 |
-
|
| 65 |
-
You can also explicitly instantiate the transport:
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
|
|
|
| 72 |
```
|
| 73 |
|
| 74 |
-
###
|
| 75 |
|
| 76 |
-
|
| 77 |
|
| 78 |
```python
|
| 79 |
-
from fastmcp import
|
| 80 |
-
from fastmcp.client.transports import StreamableHttpTransport
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
headers={"Authorization": "Bearer your-token-here"}
|
| 86 |
)
|
| 87 |
-
|
| 88 |
client = Client(transport)
|
| 89 |
```
|
| 90 |
|
| 91 |
-
|
| 92 |
|
| 93 |
```python
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
"
|
| 99 |
-
auth=BearerAuth("your-token-here"),
|
| 100 |
)
|
|
|
|
| 101 |
```
|
| 102 |
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
<VersionBadge version="2.0.0" />
|
| 106 |
-
|
| 107 |
-
Server-Sent Events (SSE) is a transport that allows servers to push data to clients over HTTP connections. While still supported, Streamable HTTP is now the recommended transport for new web-based deployments.
|
| 108 |
-
|
| 109 |
-
#### Overview
|
| 110 |
-
|
| 111 |
-
- **Class:** `fastmcp.client.transports.SSETransport`
|
| 112 |
-
- **Inferred From:** HTTP URLs containing `/sse/` in the path
|
| 113 |
-
- **Server Compatibility:** Works with FastMCP servers running in `sse` mode
|
| 114 |
-
|
| 115 |
-
#### Basic Usage
|
| 116 |
-
|
| 117 |
-
The simplest way to use SSE is to let the transport be inferred from a URL with `/sse/` in the path:
|
| 118 |
|
| 119 |
```python
|
| 120 |
from fastmcp import Client
|
| 121 |
-
import asyncio
|
| 122 |
|
| 123 |
-
|
| 124 |
-
|
| 125 |
|
| 126 |
-
|
| 127 |
-
async with client:
|
| 128 |
-
tools = await client.list_tools()
|
| 129 |
-
print(f"Available tools: {tools}")
|
| 130 |
|
| 131 |
-
|
| 132 |
-
```
|
| 133 |
|
| 134 |
-
|
| 135 |
|
| 136 |
```python
|
| 137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
-
transport =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
client = Client(transport)
|
| 141 |
```
|
| 142 |
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
SSE transport also supports custom headers for authentication:
|
| 146 |
|
| 147 |
```python
|
| 148 |
-
from
|
| 149 |
-
from fastmcp.client.transports import
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
transport =
|
| 153 |
-
|
| 154 |
-
|
|
|
|
| 155 |
)
|
| 156 |
-
|
| 157 |
client = Client(transport)
|
| 158 |
```
|
| 159 |
|
| 160 |
-
###
|
| 161 |
-
|
| 162 |
-
- **Use Streamable HTTP when:**
|
| 163 |
-
- Setting up new deployments (recommended default)
|
| 164 |
-
- You need bidirectional streaming
|
| 165 |
-
- You're connecting to FastMCP servers running in `http` mode
|
| 166 |
-
|
| 167 |
-
- **Use SSE when:**
|
| 168 |
-
- Connecting to legacy FastMCP servers running in `sse` mode
|
| 169 |
-
- Working with infrastructure optimized for Server-Sent Events
|
| 170 |
-
|
| 171 |
-
## Local Transports
|
| 172 |
|
| 173 |
-
|
| 174 |
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
All stdio transports support a `keep_alive` parameter (default: `True`) that controls session persistence across multiple client context managers:
|
| 178 |
-
|
| 179 |
-
- **`keep_alive=True` (default)**: The subprocess and session are maintained between client context exits and re-entries. This improves performance when making multiple separate connections to the same server.
|
| 180 |
-
- **`keep_alive=False`**: A new subprocess is started for each client context, ensuring complete isolation between sessions.
|
| 181 |
-
|
| 182 |
-
When `keep_alive=True`, you can manually close the session using `await client.close()` if needed. This will terminate the subprocess and require a new one to be started on the next connection.
|
| 183 |
-
|
| 184 |
-
<CodeGroup>
|
| 185 |
-
```python keep_alive=True
|
| 186 |
-
from fastmcp import Client
|
| 187 |
-
|
| 188 |
-
# Client with keep_alive=True (default)
|
| 189 |
-
client = Client("my_mcp_server.py")
|
| 190 |
-
|
| 191 |
-
async def example():
|
| 192 |
-
# First session
|
| 193 |
-
async with client:
|
| 194 |
-
await client.ping()
|
| 195 |
-
|
| 196 |
-
# Second session - uses the same subprocess
|
| 197 |
-
async with client:
|
| 198 |
-
await client.ping()
|
| 199 |
-
|
| 200 |
-
# Manually close the session
|
| 201 |
-
await client.close()
|
| 202 |
-
|
| 203 |
-
# Third session - will start a new subprocess
|
| 204 |
-
async with client:
|
| 205 |
-
await client.ping()
|
| 206 |
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
```python keep_alive=False
|
| 210 |
-
from fastmcp import Client
|
| 211 |
|
| 212 |
-
|
| 213 |
-
|
|
|
|
|
|
|
|
|
|
| 214 |
|
| 215 |
-
async def
|
| 216 |
-
# First session
|
| 217 |
async with client:
|
| 218 |
await client.ping()
|
| 219 |
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
|
| 224 |
-
|
| 225 |
-
async with client:
|
| 226 |
-
await client.ping()
|
| 227 |
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
```
|
| 230 |
-
</CodeGroup>
|
| 231 |
-
|
| 232 |
-
### Python Stdio
|
| 233 |
|
| 234 |
-
|
| 235 |
-
- **Inferred From:** Paths to `.py` files
|
| 236 |
-
- **Use Case:** Running a Python-based MCP server script in a subprocess
|
| 237 |
|
| 238 |
-
|
| 239 |
|
| 240 |
-
``
|
| 241 |
-
from fastmcp import Client
|
| 242 |
-
from fastmcp.client.transports import PythonStdioTransport
|
| 243 |
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
-
|
| 247 |
-
client = Client(server_script)
|
| 248 |
|
| 249 |
-
#
|
| 250 |
-
transport = PythonStdioTransport(
|
| 251 |
-
script_path=server_script,
|
| 252 |
-
python_cmd="/usr/bin/python3.11", # Optional: specify Python interpreter
|
| 253 |
-
# args=["--some-server-arg"], # Optional: pass arguments to the script
|
| 254 |
-
# env={"MY_VAR": "value"}, # Optional: set environment variables
|
| 255 |
-
)
|
| 256 |
-
client = Client(transport)
|
| 257 |
|
| 258 |
-
|
| 259 |
-
async with client:
|
| 260 |
-
tools = await client.list_tools()
|
| 261 |
-
print(f"Connected via Python Stdio, found tools: {tools}")
|
| 262 |
|
| 263 |
-
|
| 264 |
-
```
|
| 265 |
|
| 266 |
-
<
|
| 267 |
-
The server script must include logic to start the MCP server and listen on stdio, typically via `mcp.run()` or `fastmcp.server.run()`. The Client only launches the script; it doesn't inject the server logic.
|
| 268 |
-
</Warning>
|
| 269 |
|
| 270 |
-
|
| 271 |
|
| 272 |
-
- **Class:** `
|
| 273 |
-
- **
|
| 274 |
-
- **Use Case:** Running a Node.js-based MCP server script in a subprocess
|
| 275 |
|
| 276 |
-
|
| 277 |
|
| 278 |
```python
|
| 279 |
-
from fastmcp import
|
| 280 |
-
from fastmcp.client.transports import NodeStdioTransport
|
| 281 |
-
|
| 282 |
-
node_server_script = "my_mcp_server.js" # Path to your Node.js server script
|
| 283 |
|
| 284 |
-
#
|
| 285 |
-
|
|
|
|
| 286 |
|
| 287 |
-
#
|
| 288 |
-
transport =
|
| 289 |
-
|
| 290 |
-
|
|
|
|
|
|
|
|
|
|
| 291 |
)
|
| 292 |
client = Client(transport)
|
| 293 |
-
|
| 294 |
-
async def main():
|
| 295 |
-
async with client:
|
| 296 |
-
tools = await client.list_tools()
|
| 297 |
-
print(f"Connected via Node.js Stdio, found tools: {tools}")
|
| 298 |
-
|
| 299 |
-
asyncio.run(main())
|
| 300 |
```
|
| 301 |
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
- **Class:** `fastmcp.client.transports.UvxStdioTransport`
|
| 305 |
-
- **Inferred From:** Not automatically inferred
|
| 306 |
-
- **Use Case:** Running an MCP server packaged as a Python tool using [`uvx`](https://docs.astral.sh/uv/reference/cli/#uvx)
|
| 307 |
-
|
| 308 |
-
This is useful for executing MCP servers distributed as command-line tools or packages without installing them into your environment.
|
| 309 |
|
| 310 |
```python
|
| 311 |
-
from fastmcp import
|
| 312 |
-
from fastmcp.client.transports import UvxStdioTransport
|
| 313 |
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
# from_package="cloud-analyzer-cli", # Optional: specify package if tool name differs
|
| 318 |
-
# with_packages=["boto3", "requests"] # Optional: add dependencies
|
| 319 |
)
|
| 320 |
-
client = Client(transport)
|
| 321 |
-
|
| 322 |
-
async def main():
|
| 323 |
-
async with client:
|
| 324 |
-
result = await client.call_tool("analyze_bucket", {"name": "my-data"})
|
| 325 |
-
print(f"Analysis result: {result}")
|
| 326 |
-
|
| 327 |
-
asyncio.run(main())
|
| 328 |
```
|
| 329 |
|
| 330 |
-
###
|
|
|
|
|
|
|
| 331 |
|
| 332 |
-
- **Class:** `
|
| 333 |
-
- **
|
| 334 |
-
- **Use Case:** Running an MCP server packaged as an NPM package using `npx`
|
| 335 |
|
| 336 |
-
|
| 337 |
|
| 338 |
```python
|
| 339 |
-
from fastmcp import
|
| 340 |
-
from fastmcp.client.transports import NpxStdioTransport
|
| 341 |
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
# args=["--port", "stdio"] # Optional: pass arguments to the package
|
| 346 |
)
|
| 347 |
client = Client(transport)
|
| 348 |
-
|
| 349 |
-
async def main():
|
| 350 |
-
async with client:
|
| 351 |
-
result = await client.call_tool("get_npm_data", {})
|
| 352 |
-
print(f"Result: {result}")
|
| 353 |
-
|
| 354 |
-
asyncio.run(main())
|
| 355 |
```
|
| 356 |
|
| 357 |
-
|
| 358 |
|
| 359 |
-
##
|
| 360 |
|
| 361 |
-
-
|
| 362 |
-
- **Inferred From:** An instance of `fastmcp.server.FastMCP` or a **FastMCP 1.0 server** (`mcp.server.fastmcp.FastMCP`)
|
| 363 |
-
- **Use Case:** Connecting directly to a FastMCP server instance in the same Python process
|
| 364 |
|
| 365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
|
| 367 |
```python
|
| 368 |
from fastmcp import FastMCP, Client
|
| 369 |
-
import
|
| 370 |
-
|
| 371 |
-
# 1. Create your FastMCP server instance
|
| 372 |
-
server = FastMCP(name="InMemoryServer")
|
| 373 |
|
| 374 |
-
|
| 375 |
-
def ping():
|
| 376 |
-
return "pong"
|
| 377 |
|
| 378 |
-
|
| 379 |
-
|
|
|
|
|
|
|
| 380 |
|
| 381 |
-
|
| 382 |
-
async with client:
|
| 383 |
-
result = await client.call_tool("ping")
|
| 384 |
-
print(f"In-memory call result: {result}")
|
| 385 |
|
| 386 |
-
|
|
|
|
| 387 |
```
|
| 388 |
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
## Configuration-Based Transports
|
| 392 |
-
|
| 393 |
-
### MCPConfig Transport
|
| 394 |
|
| 395 |
<VersionBadge version="2.4.0" />
|
| 396 |
|
| 397 |
-
|
| 398 |
-
- **Inferred From:** An instance of `MCPConfig` or a dictionary matching the MCPConfig schema
|
| 399 |
-
- **Use Case:** Connecting to one or more MCP servers defined in a configuration object
|
| 400 |
|
| 401 |
-
|
| 402 |
|
| 403 |
```python
|
| 404 |
-
from fastmcp import Client
|
| 405 |
-
|
| 406 |
-
# Configuration for multiple MCP servers (both local and remote)
|
| 407 |
config = {
|
| 408 |
"mcpServers": {
|
| 409 |
-
# Remote HTTP server
|
| 410 |
"weather": {
|
| 411 |
-
"url": "https://weather
|
| 412 |
"transport": "http"
|
| 413 |
},
|
| 414 |
-
# Local stdio server
|
| 415 |
"assistant": {
|
| 416 |
"command": "python",
|
| 417 |
-
"args": ["./
|
| 418 |
-
"env": {"
|
| 419 |
-
},
|
| 420 |
-
# Another remote server
|
| 421 |
-
"calendar": {
|
| 422 |
-
"url": "https://calendar-api.example.com/mcp",
|
| 423 |
-
"transport": "http"
|
| 424 |
}
|
| 425 |
}
|
| 426 |
}
|
| 427 |
|
| 428 |
-
# Create a transport from the config (happens automatically with Client)
|
| 429 |
client = Client(config)
|
| 430 |
|
| 431 |
-
async
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
answer = await client.call_tool("assistant_answer_question", {"query": "What is MCP?"})
|
| 436 |
-
events = await client.call_tool("calendar_list_events", {"date": "2023-06-01"})
|
| 437 |
-
|
| 438 |
-
# Resources use prefixed URI paths
|
| 439 |
-
icons = await client.read_resource("weather://weather/icons/sunny")
|
| 440 |
-
docs = await client.read_resource("resource://assistant/docs/mcp")
|
| 441 |
-
|
| 442 |
-
asyncio.run(main())
|
| 443 |
```
|
| 444 |
|
| 445 |
-
If your configuration has only a single server, the client will connect directly to that server without any prefixing. This makes it convenient to switch between single and multi-server configurations without changing your client code.
|
| 446 |
-
|
| 447 |
-
<Note>
|
| 448 |
-
The MCPConfig format is an emerging standard for MCP server configuration and may change as the MCP ecosystem evolves. While FastMCP aims to maintain compatibility with future versions, be aware that field names or structure might change.
|
| 449 |
-
</Note>
|
|
|
|
| 1 |
---
|
| 2 |
title: Client Transports
|
| 3 |
sidebarTitle: Transports
|
| 4 |
+
description: Configure how FastMCP Clients connect to and communicate with servers.
|
| 5 |
icon: link
|
| 6 |
---
|
| 7 |
|
|
|
|
| 9 |
|
| 10 |
<VersionBadge version="2.0.0" />
|
| 11 |
|
| 12 |
+
The FastMCP `Client` communicates with MCP servers through transport objects that handle the underlying connection mechanics. While the client can automatically select a transport based on what you pass to it, instantiating transports explicitly gives you full control over configuration—environment variables, authentication, session management, and more.
|
| 13 |
|
| 14 |
+
Think of transports as configurable adapters between your client code and MCP servers. Each transport type handles a different communication pattern: subprocesses with pipes, HTTP connections, or direct in-memory calls.
|
| 15 |
|
| 16 |
+
## Choosing the Right Transport
|
|
|
|
|
|
|
| 17 |
|
| 18 |
+
- **Use [STDIO Transport](#stdio-transport)** when you need to run local MCP servers with full control over their environment and lifecycle
|
| 19 |
+
- **Use [Remote Transports](#remote-transports)** when connecting to production services or shared MCP servers running independently
|
| 20 |
+
- **Use [In-Memory Transport](#in-memory-transport)** for testing FastMCP servers without subprocess or network overhead
|
| 21 |
+
- **Use [MCP JSON Configuration](#mcp-json-configuration-transport)** when you need to connect to multiple servers defined in configuration files
|
| 22 |
|
| 23 |
+
## STDIO Transport
|
| 24 |
|
| 25 |
+
STDIO (Standard Input/Output) transport communicates with MCP servers through subprocess pipes. This is the standard mechanism used by desktop clients like Claude Desktop and is the primary way to run local MCP servers.
|
| 26 |
|
| 27 |
+
### The Client Runs the Server
|
| 28 |
|
| 29 |
+
<Warning>
|
| 30 |
+
**Critical Concept**: When using STDIO transport, your client actually launches and manages the server process. This is fundamentally different from network transports where you connect to an already-running server. Understanding this relationship is key to using STDIO effectively.
|
| 31 |
+
</Warning>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
With STDIO transport, your client:
|
| 34 |
+
- Starts the server as a subprocess when you connect
|
| 35 |
+
- Manages the server's lifecycle (start, stop, restart)
|
| 36 |
+
- Controls the server's environment and configuration
|
| 37 |
+
- Communicates through stdin/stdout pipes
|
| 38 |
|
| 39 |
+
This architecture enables powerful local integrations but requires understanding environment isolation and process management.
|
| 40 |
|
| 41 |
+
### Environment Isolation
|
| 42 |
|
| 43 |
+
STDIO servers run in isolated environments by default. This is a security feature enforced by the MCP protocol to prevent accidental exposure of sensitive data.
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
When your client launches an MCP server:
|
| 46 |
+
- The server does NOT inherit your shell's environment variables
|
| 47 |
+
- API keys, paths, and other configuration must be explicitly passed
|
| 48 |
+
- The working directory and system paths may differ from your shell
|
| 49 |
|
| 50 |
+
To pass environment variables to your server, use the `env` parameter:
|
| 51 |
|
| 52 |
```python
|
| 53 |
from fastmcp import Client
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
# If your server needs environment variables (like API keys),
|
| 56 |
+
# you must explicitly pass them:
|
| 57 |
+
client = Client(
|
| 58 |
+
"my_server.py",
|
| 59 |
+
env={"API_KEY": "secret", "DEBUG": "true"}
|
| 60 |
+
)
|
| 61 |
|
| 62 |
+
# This won't work - the server runs in isolation:
|
| 63 |
+
# export API_KEY="secret" # in your shell
|
| 64 |
+
# client = Client("my_server.py") # server can't see API_KEY
|
| 65 |
```
|
| 66 |
|
| 67 |
+
### Basic Usage
|
| 68 |
|
| 69 |
+
To use STDIO transport, you create a transport instance with the command and arguments needed to run your server:
|
| 70 |
|
| 71 |
```python
|
| 72 |
+
from fastmcp.client.transports import StdioTransport
|
|
|
|
| 73 |
|
| 74 |
+
transport = StdioTransport(
|
| 75 |
+
command="python",
|
| 76 |
+
args=["my_server.py"]
|
|
|
|
| 77 |
)
|
|
|
|
| 78 |
client = Client(transport)
|
| 79 |
```
|
| 80 |
|
| 81 |
+
You can configure additional settings like environment variables, working directory, or command arguments:
|
| 82 |
|
| 83 |
```python
|
| 84 |
+
transport = StdioTransport(
|
| 85 |
+
command="python",
|
| 86 |
+
args=["my_server.py", "--verbose"],
|
| 87 |
+
env={"LOG_LEVEL": "DEBUG"},
|
| 88 |
+
cwd="/path/to/server"
|
|
|
|
| 89 |
)
|
| 90 |
+
client = Client(transport)
|
| 91 |
```
|
| 92 |
|
| 93 |
+
For convenience, the client can also infer STDIO transport from file paths, but this doesn't allow configuration:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
```python
|
| 96 |
from fastmcp import Client
|
|
|
|
| 97 |
|
| 98 |
+
client = Client("my_server.py") # Limited - no configuration options
|
| 99 |
+
```
|
| 100 |
|
| 101 |
+
### Environment Variables
|
|
|
|
|
|
|
|
|
|
| 102 |
|
| 103 |
+
Since STDIO servers don't inherit your environment, you need strategies for passing configuration. Here are two common approaches:
|
|
|
|
| 104 |
|
| 105 |
+
**Selective forwarding** passes only the variables your server actually needs:
|
| 106 |
|
| 107 |
```python
|
| 108 |
+
import os
|
| 109 |
+
from fastmcp.client.transports import StdioTransport
|
| 110 |
+
|
| 111 |
+
required_vars = ["API_KEY", "DATABASE_URL", "REDIS_HOST"]
|
| 112 |
+
env = {
|
| 113 |
+
var: os.environ[var]
|
| 114 |
+
for var in required_vars
|
| 115 |
+
if var in os.environ
|
| 116 |
+
}
|
| 117 |
|
| 118 |
+
transport = StdioTransport(
|
| 119 |
+
command="python",
|
| 120 |
+
args=["server.py"],
|
| 121 |
+
env=env
|
| 122 |
+
)
|
| 123 |
client = Client(transport)
|
| 124 |
```
|
| 125 |
|
| 126 |
+
**Loading from .env files** keeps configuration separate from code:
|
|
|
|
|
|
|
| 127 |
|
| 128 |
```python
|
| 129 |
+
from dotenv import dotenv_values
|
| 130 |
+
from fastmcp.client.transports import StdioTransport
|
| 131 |
+
|
| 132 |
+
env = dotenv_values(".env")
|
| 133 |
+
transport = StdioTransport(
|
| 134 |
+
command="python",
|
| 135 |
+
args=["server.py"],
|
| 136 |
+
env=env
|
| 137 |
)
|
|
|
|
| 138 |
client = Client(transport)
|
| 139 |
```
|
| 140 |
|
| 141 |
+
### Session Persistence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
|
| 143 |
+
STDIO transports maintain sessions across multiple client contexts by default (`keep_alive=True`). This improves performance by reusing the same subprocess for multiple connections, but can be controlled when you need isolation.
|
| 144 |
|
| 145 |
+
By default, the subprocess persists between connections:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
+
```python
|
| 148 |
+
from fastmcp.client.transports import StdioTransport
|
|
|
|
|
|
|
| 149 |
|
| 150 |
+
transport = StdioTransport(
|
| 151 |
+
command="python",
|
| 152 |
+
args=["server.py"]
|
| 153 |
+
)
|
| 154 |
+
client = Client(transport)
|
| 155 |
|
| 156 |
+
async def efficient_multiple_operations():
|
|
|
|
| 157 |
async with client:
|
| 158 |
await client.ping()
|
| 159 |
|
| 160 |
+
async with client: # Reuses the same subprocess
|
| 161 |
+
await client.call_tool("process_data", {"file": "data.csv"})
|
| 162 |
+
```
|
| 163 |
|
| 164 |
+
For complete isolation between connections, disable session persistence:
|
|
|
|
|
|
|
| 165 |
|
| 166 |
+
```python
|
| 167 |
+
transport = StdioTransport(
|
| 168 |
+
command="python",
|
| 169 |
+
args=["server.py"],
|
| 170 |
+
keep_alive=False
|
| 171 |
+
)
|
| 172 |
+
client = Client(transport)
|
| 173 |
```
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
+
Use `keep_alive=False` when you need complete isolation (e.g., in test suites) or when server state could cause issues between connections.
|
|
|
|
|
|
|
| 176 |
|
| 177 |
+
### Specialized STDIO Transports
|
| 178 |
|
| 179 |
+
FastMCP provides convenience transports that are thin wrappers around `StdioTransport` with pre-configured commands:
|
|
|
|
|
|
|
| 180 |
|
| 181 |
+
- **`PythonStdioTransport`** - Uses `python` command for `.py` files
|
| 182 |
+
- **`NodeStdioTransport`** - Uses `node` command for `.js` files
|
| 183 |
+
- **`UvxStdioTransport`** - Uses `uvx` for Python packages (uses `env_vars` parameter)
|
| 184 |
+
- **`NpxStdioTransport`** - Uses `npx` for Node packages (uses `env_vars` parameter)
|
| 185 |
|
| 186 |
+
For most use cases, instantiate `StdioTransport` directly with your desired command. These specialized transports are primarily useful for client inference shortcuts.
|
|
|
|
| 187 |
|
| 188 |
+
## Remote Transports
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
+
Remote transports connect to MCP servers running as web services. This is a fundamentally different model from STDIO transports—instead of your client launching and managing a server process, you connect to an already-running service that manages its own environment and lifecycle.
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
+
### Streamable HTTP Transport
|
|
|
|
| 193 |
|
| 194 |
+
<VersionBadge version="2.3.0" />
|
|
|
|
|
|
|
| 195 |
|
| 196 |
+
Streamable HTTP is the recommended transport for production deployments, providing efficient bidirectional streaming over HTTP connections.
|
| 197 |
|
| 198 |
+
- **Class:** `StreamableHttpTransport`
|
| 199 |
+
- **Server compatibility:** FastMCP servers running with `mcp run --transport http`
|
|
|
|
| 200 |
|
| 201 |
+
The transport requires a URL and optionally supports custom headers for authentication and configuration:
|
| 202 |
|
| 203 |
```python
|
| 204 |
+
from fastmcp.client.transports import StreamableHttpTransport
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
+
# Basic connection
|
| 207 |
+
transport = StreamableHttpTransport(url="https://api.example.com/mcp")
|
| 208 |
+
client = Client(transport)
|
| 209 |
|
| 210 |
+
# With custom headers for authentication
|
| 211 |
+
transport = StreamableHttpTransport(
|
| 212 |
+
url="https://api.example.com/mcp",
|
| 213 |
+
headers={
|
| 214 |
+
"Authorization": "Bearer your-token-here",
|
| 215 |
+
"X-Custom-Header": "value"
|
| 216 |
+
}
|
| 217 |
)
|
| 218 |
client = Client(transport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
```
|
| 220 |
|
| 221 |
+
For convenience, FastMCP also provides authentication helpers:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
```python
|
| 224 |
+
from fastmcp.client.auth import BearerAuth
|
|
|
|
| 225 |
|
| 226 |
+
client = Client(
|
| 227 |
+
"https://api.example.com/mcp",
|
| 228 |
+
auth=BearerAuth("your-token-here")
|
|
|
|
|
|
|
| 229 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
```
|
| 231 |
|
| 232 |
+
### SSE Transport (Legacy)
|
| 233 |
+
|
| 234 |
+
Server-Sent Events transport is maintained for backward compatibility but is superseded by Streamable HTTP for new deployments.
|
| 235 |
|
| 236 |
+
- **Class:** `SSETransport`
|
| 237 |
+
- **Server compatibility:** FastMCP servers running with `mcp run --transport sse`
|
|
|
|
| 238 |
|
| 239 |
+
SSE transport supports the same configuration options as Streamable HTTP:
|
| 240 |
|
| 241 |
```python
|
| 242 |
+
from fastmcp.client.transports import SSETransport
|
|
|
|
| 243 |
|
| 244 |
+
transport = SSETransport(
|
| 245 |
+
url="https://api.example.com/sse",
|
| 246 |
+
headers={"Authorization": "Bearer token"}
|
|
|
|
| 247 |
)
|
| 248 |
client = Client(transport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
```
|
| 250 |
|
| 251 |
+
Use Streamable HTTP for new deployments unless you have specific infrastructure requirements for SSE.
|
| 252 |
|
| 253 |
+
## In-Memory Transport
|
| 254 |
|
| 255 |
+
In-memory transport connects directly to a FastMCP server instance within the same Python process. This eliminates both subprocess management and network overhead, making it ideal for testing and development.
|
|
|
|
|
|
|
| 256 |
|
| 257 |
+
- **Class:** `FastMCPTransport`
|
| 258 |
+
|
| 259 |
+
<Note>
|
| 260 |
+
Unlike STDIO transports, in-memory servers have full access to your Python process's environment. They share the same memory space and environment variables as your client code—no isolation or explicit environment passing required.
|
| 261 |
+
</Note>
|
| 262 |
|
| 263 |
```python
|
| 264 |
from fastmcp import FastMCP, Client
|
| 265 |
+
import os
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
+
mcp = FastMCP("TestServer")
|
|
|
|
|
|
|
| 268 |
|
| 269 |
+
@mcp.tool
|
| 270 |
+
def greet(name: str) -> str:
|
| 271 |
+
prefix = os.environ.get("GREETING_PREFIX", "Hello")
|
| 272 |
+
return f"{prefix}, {name}!"
|
| 273 |
|
| 274 |
+
client = Client(mcp)
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
+
async with client:
|
| 277 |
+
result = await client.call_tool("greet", {"name": "World"})
|
| 278 |
```
|
| 279 |
|
| 280 |
+
## MCP JSON Configuration Transport
|
|
|
|
|
|
|
|
|
|
|
|
|
| 281 |
|
| 282 |
<VersionBadge version="2.4.0" />
|
| 283 |
|
| 284 |
+
This transport supports the emerging MCP JSON configuration standard for defining multiple servers:
|
|
|
|
|
|
|
| 285 |
|
| 286 |
+
- **Class:** `MCPConfigTransport`
|
| 287 |
|
| 288 |
```python
|
|
|
|
|
|
|
|
|
|
| 289 |
config = {
|
| 290 |
"mcpServers": {
|
|
|
|
| 291 |
"weather": {
|
| 292 |
+
"url": "https://weather.example.com/mcp",
|
| 293 |
"transport": "http"
|
| 294 |
},
|
|
|
|
| 295 |
"assistant": {
|
| 296 |
"command": "python",
|
| 297 |
+
"args": ["./assistant.py"],
|
| 298 |
+
"env": {"LOG_LEVEL": "INFO"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
}
|
| 300 |
}
|
| 301 |
}
|
| 302 |
|
|
|
|
| 303 |
client = Client(config)
|
| 304 |
|
| 305 |
+
async with client:
|
| 306 |
+
# Tools are namespaced by server
|
| 307 |
+
weather = await client.call_tool("weather_get_forecast", {"city": "NYC"})
|
| 308 |
+
answer = await client.call_tool("assistant_ask", {"question": "What?"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
```
|
| 310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/docs.json
CHANGED
|
@@ -62,7 +62,11 @@
|
|
| 62 |
{
|
| 63 |
"group": "Servers",
|
| 64 |
"pages": [
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
{
|
| 67 |
"group": "Core Components",
|
| 68 |
"icon": "toolbox",
|
|
@@ -80,29 +84,27 @@
|
|
| 80 |
"servers/elicitation",
|
| 81 |
"servers/logging",
|
| 82 |
"servers/progress",
|
| 83 |
-
"servers/sampling"
|
|
|
|
|
|
|
|
|
|
| 84 |
]
|
| 85 |
},
|
| 86 |
{
|
| 87 |
"group": "Authentication",
|
| 88 |
"icon": "shield-check",
|
| 89 |
"pages": ["servers/auth/bearer"]
|
| 90 |
-
},
|
| 91 |
-
"servers/middleware",
|
| 92 |
-
"servers/openapi",
|
| 93 |
-
"servers/proxy",
|
| 94 |
-
"servers/composition",
|
| 95 |
-
{
|
| 96 |
-
"group": "Deployment",
|
| 97 |
-
"icon": "upload",
|
| 98 |
-
"pages": ["deployment/running-server", "deployment/asgi"]
|
| 99 |
}
|
| 100 |
]
|
| 101 |
},
|
| 102 |
{
|
| 103 |
"group": "Clients",
|
| 104 |
"pages": [
|
| 105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
{
|
| 107 |
"group": "Core Operations",
|
| 108 |
"icon": "handshake",
|
|
@@ -124,7 +126,6 @@
|
|
| 124 |
"clients/roots"
|
| 125 |
]
|
| 126 |
},
|
| 127 |
-
"clients/transports",
|
| 128 |
{
|
| 129 |
"group": "Authentication",
|
| 130 |
"icon": "user-shield",
|
|
@@ -141,9 +142,12 @@
|
|
| 141 |
"integrations/claude-desktop",
|
| 142 |
"integrations/cursor",
|
| 143 |
"integrations/eunomia-authorization",
|
|
|
|
| 144 |
"integrations/gemini",
|
| 145 |
"integrations/mcp-json-configuration",
|
| 146 |
-
"integrations/openai"
|
|
|
|
|
|
|
| 147 |
]
|
| 148 |
},
|
| 149 |
{
|
|
|
|
| 62 |
{
|
| 63 |
"group": "Servers",
|
| 64 |
"pages": [
|
| 65 |
+
{
|
| 66 |
+
"group": "Essentials",
|
| 67 |
+
"icon": "cube",
|
| 68 |
+
"pages": ["servers/server", "deployment/running-server"]
|
| 69 |
+
},
|
| 70 |
{
|
| 71 |
"group": "Core Components",
|
| 72 |
"icon": "toolbox",
|
|
|
|
| 84 |
"servers/elicitation",
|
| 85 |
"servers/logging",
|
| 86 |
"servers/progress",
|
| 87 |
+
"servers/sampling",
|
| 88 |
+
"servers/middleware",
|
| 89 |
+
"servers/composition",
|
| 90 |
+
"servers/proxy"
|
| 91 |
]
|
| 92 |
},
|
| 93 |
{
|
| 94 |
"group": "Authentication",
|
| 95 |
"icon": "shield-check",
|
| 96 |
"pages": ["servers/auth/bearer"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
}
|
| 98 |
]
|
| 99 |
},
|
| 100 |
{
|
| 101 |
"group": "Clients",
|
| 102 |
"pages": [
|
| 103 |
+
{
|
| 104 |
+
"group": "Essentials",
|
| 105 |
+
"icon": "cube",
|
| 106 |
+
"pages": ["clients/client", "clients/transports"]
|
| 107 |
+
},
|
| 108 |
{
|
| 109 |
"group": "Core Operations",
|
| 110 |
"icon": "handshake",
|
|
|
|
| 126 |
"clients/roots"
|
| 127 |
]
|
| 128 |
},
|
|
|
|
| 129 |
{
|
| 130 |
"group": "Authentication",
|
| 131 |
"icon": "user-shield",
|
|
|
|
| 142 |
"integrations/claude-desktop",
|
| 143 |
"integrations/cursor",
|
| 144 |
"integrations/eunomia-authorization",
|
| 145 |
+
"integrations/fastapi",
|
| 146 |
"integrations/gemini",
|
| 147 |
"integrations/mcp-json-configuration",
|
| 148 |
+
"integrations/openai",
|
| 149 |
+
"integrations/openapi",
|
| 150 |
+
"integrations/starlette"
|
| 151 |
]
|
| 152 |
},
|
| 153 |
{
|
docs/integrations/fastapi.mdx
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: FastAPI 🤝 FastMCP
|
| 3 |
+
sidebarTitle: FastAPI
|
| 4 |
+
description: Integrate FastMCP with FastAPI applications
|
| 5 |
+
icon: bolt
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
import { VersionBadge } from '/snippets/version-badge.mdx'
|
| 9 |
+
|
| 10 |
+
FastMCP provides two powerful ways to integrate with FastAPI applications, both of which are documented below.
|
| 11 |
+
|
| 12 |
+
1. You can [generate an MCP server FROM your FastAPI app](#generating-an-mcp-server) by converting existing API endpoints into MCP tools. This is useful for bootstrapping and quickly attaching LLMs to your API.
|
| 13 |
+
2. You can [mount an MCP server INTO your FastAPI app](#mounting-an-mcp-server) by adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints.
|
| 14 |
+
|
| 15 |
+
You can even combine both approaches to create a single FastAPI app that serves both regular API endpoints and MCP tools!
|
| 16 |
+
|
| 17 |
+
<Tip>
|
| 18 |
+
Generating MCP servers from FastAPI apps is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted FastAPI servers. This is especially true for complex APIs with many endpoints and parameters.
|
| 19 |
+
</Tip>
|
| 20 |
+
|
| 21 |
+
<Note>
|
| 22 |
+
FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration.
|
| 23 |
+
</Note>
|
| 24 |
+
|
| 25 |
+
## Generating an MCP Server
|
| 26 |
+
|
| 27 |
+
<VersionBadge version="2.0.0" />
|
| 28 |
+
|
| 29 |
+
FastMCP can directly convert your existing FastAPI applications into MCP servers, allowing AI models to interact with your API endpoints through the MCP protocol.
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
<Tip>
|
| 33 |
+
Under the hood, the FastAPI integration is built on top of FastMCP's OpenAPI integration. See the [OpenAPI docs](/integrations/openapi) for more details.
|
| 34 |
+
</Tip>
|
| 35 |
+
|
| 36 |
+
### Create a Server
|
| 37 |
+
|
| 38 |
+
The simplest way to convert a FastAPI app is using the `FastMCP.from_fastapi()` method:
|
| 39 |
+
|
| 40 |
+
```python server.py
|
| 41 |
+
from fastapi import FastAPI
|
| 42 |
+
from fastmcp import FastMCP
|
| 43 |
+
|
| 44 |
+
# Your existing FastAPI app
|
| 45 |
+
app = FastAPI(title="My API", version="1.0.0")
|
| 46 |
+
|
| 47 |
+
@app.get("/items", tags=["items"], operation_id="list_items")
|
| 48 |
+
def list_items():
|
| 49 |
+
return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}]
|
| 50 |
+
|
| 51 |
+
@app.get("/items/{item_id}", tags=["items", "detail"], operation_id="get_item")
|
| 52 |
+
def get_item(item_id: int):
|
| 53 |
+
return {"id": item_id, "name": f"Item {item_id}"}
|
| 54 |
+
|
| 55 |
+
@app.post("/items", tags=["items", "create"], operation_id="create_item")
|
| 56 |
+
def create_item(name: str):
|
| 57 |
+
return {"id": 3, "name": name}
|
| 58 |
+
|
| 59 |
+
# Convert FastAPI app to MCP server
|
| 60 |
+
mcp = FastMCP.from_fastapi(app=app)
|
| 61 |
+
|
| 62 |
+
if __name__ == "__main__":
|
| 63 |
+
mcp.run() # Run as MCP server
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### Component Mapping
|
| 67 |
+
|
| 68 |
+
By default, FastMCP converts **every endpoint** in your FastAPI app into an MCP **Tool**. This provides maximum compatibility with LLM clients that primarily support MCP tools.
|
| 69 |
+
|
| 70 |
+
You can customize this behavior using route maps to control which endpoints become tools, resources, or resource templates:
|
| 71 |
+
|
| 72 |
+
```python
|
| 73 |
+
from fastmcp.server.openapi import RouteMap, MCPType
|
| 74 |
+
|
| 75 |
+
# Custom route mapping
|
| 76 |
+
mcp = FastMCP.from_fastapi(
|
| 77 |
+
app=app,
|
| 78 |
+
route_maps=[
|
| 79 |
+
# GET requests with path parameters become ResourceTemplates
|
| 80 |
+
RouteMap(methods=["GET"], pattern=r".*\{.*\}.*", mcp_type=MCPType.RESOURCE_TEMPLATE),
|
| 81 |
+
# All other GET requests become Resources
|
| 82 |
+
RouteMap(methods=["GET"], pattern=r".*", mcp_type=MCPType.RESOURCE),
|
| 83 |
+
# POST/PUT/DELETE become Tools (handled by default rule)
|
| 84 |
+
],
|
| 85 |
+
)
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
The `FastMCP.from_fastapi()` method accepts all the same configuration options as `FastMCP.from_openapi()`, including route maps, custom tags, component naming, timeouts, and component customization functions. For comprehensive configuration details, see the [OpenAPI Integration guide](/integrations/openapi).
|
| 89 |
+
|
| 90 |
+
### Key Considerations
|
| 91 |
+
|
| 92 |
+
#### Operation IDs
|
| 93 |
+
|
| 94 |
+
FastMCP uses your FastAPI operation IDs to name MCP components. Ensure your endpoints have meaningful operation IDs:
|
| 95 |
+
|
| 96 |
+
```python
|
| 97 |
+
@app.get("/users/{user_id}", operation_id="get_user_detail") # ✅ Good
|
| 98 |
+
@app.get("/users/{user_id}") # ❌ Auto-generated name might be unclear
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
#### Pydantic Models
|
| 102 |
+
|
| 103 |
+
Your Pydantic models are automatically converted to JSON schema for MCP tool parameters:
|
| 104 |
+
|
| 105 |
+
```python
|
| 106 |
+
from pydantic import BaseModel
|
| 107 |
+
|
| 108 |
+
class CreateItemRequest(BaseModel):
|
| 109 |
+
name: str
|
| 110 |
+
description: str | None = None
|
| 111 |
+
price: float
|
| 112 |
+
|
| 113 |
+
@app.post("/items")
|
| 114 |
+
def create_item(item: CreateItemRequest):
|
| 115 |
+
return {"id": 123, **item.dict()}
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
The MCP tool will have properly typed parameters matching your Pydantic model.
|
| 119 |
+
|
| 120 |
+
#### Error Handling
|
| 121 |
+
|
| 122 |
+
FastAPI error handling carries over to the MCP server. HTTPExceptions are automatically converted to appropriate MCP errors.
|
| 123 |
+
|
| 124 |
+
Since FastAPI integration is built on OpenAPI, all the same configuration options are available including authentication setup, timeout configuration, and request parameter handling. For detailed information on these features, see the [OpenAPI Integration guide](/integrations/openapi).
|
| 125 |
+
|
| 126 |
+
## Mounting an MCP Server
|
| 127 |
+
|
| 128 |
+
<VersionBadge version="2.3.1" />
|
| 129 |
+
|
| 130 |
+
You can also mount an existing FastMCP server into your FastAPI application, adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints.
|
| 131 |
+
|
| 132 |
+
### Basic Integration
|
| 133 |
+
|
| 134 |
+
```python
|
| 135 |
+
from fastmcp import FastMCP
|
| 136 |
+
from fastapi import FastAPI
|
| 137 |
+
from starlette.routing import Mount
|
| 138 |
+
|
| 139 |
+
# Create your FastMCP server
|
| 140 |
+
mcp = FastMCP("MyServer")
|
| 141 |
+
|
| 142 |
+
@mcp.tool
|
| 143 |
+
def analyze_data(query: str) -> dict:
|
| 144 |
+
"""Analyze data based on the query."""
|
| 145 |
+
return {"result": f"Analysis for: {query}"}
|
| 146 |
+
|
| 147 |
+
# Create the ASGI app from your MCP server
|
| 148 |
+
mcp_app = mcp.http_app(path='/mcp')
|
| 149 |
+
|
| 150 |
+
# Create a FastAPI app and mount the MCP server
|
| 151 |
+
app = FastAPI(lifespan=mcp_app.lifespan)
|
| 152 |
+
app.mount("/mcp-server", mcp_app)
|
| 153 |
+
|
| 154 |
+
# Add regular FastAPI routes
|
| 155 |
+
@app.get("/health")
|
| 156 |
+
def health_check():
|
| 157 |
+
return {"status": "healthy"}
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
The MCP endpoint will be available at `/mcp-server/mcp/` of your FastAPI application.
|
| 161 |
+
|
| 162 |
+
<Warning>
|
| 163 |
+
For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the FastAPI app. Otherwise, the FastMCP server's session manager will not be properly initialized.
|
| 164 |
+
</Warning>
|
| 165 |
+
|
| 166 |
+
### Advanced Integration
|
| 167 |
+
|
| 168 |
+
You can combine both approaches - generate an MCP server from your FastAPI app AND mount additional MCP servers:
|
| 169 |
+
|
| 170 |
+
```python
|
| 171 |
+
from fastmcp import FastMCP
|
| 172 |
+
from fastapi import FastAPI
|
| 173 |
+
|
| 174 |
+
# Your existing FastAPI app
|
| 175 |
+
app = FastAPI()
|
| 176 |
+
|
| 177 |
+
@app.get("/items")
|
| 178 |
+
def list_items():
|
| 179 |
+
return [{"id": 1, "name": "Item 1"}]
|
| 180 |
+
|
| 181 |
+
# Generate MCP server from FastAPI app
|
| 182 |
+
api_mcp = FastMCP.from_fastapi(app=app, name="API Server")
|
| 183 |
+
|
| 184 |
+
# Create additional purpose-built MCP server
|
| 185 |
+
tools_mcp = FastMCP("Tools Server")
|
| 186 |
+
|
| 187 |
+
@tools_mcp.tool
|
| 188 |
+
def advanced_analysis(data: dict) -> dict:
|
| 189 |
+
"""Perform advanced analysis not available via API."""
|
| 190 |
+
return {"analysis": "complex results"}
|
| 191 |
+
|
| 192 |
+
# Mount the tools server into the same FastAPI app
|
| 193 |
+
tools_app = tools_mcp.http_app(path='/mcp')
|
| 194 |
+
app.mount("/tools", tools_app, lifespan=tools_app.lifespan)
|
| 195 |
+
```
|
| 196 |
+
|
| 197 |
+
Now you have:
|
| 198 |
+
- API endpoints converted to MCP tools (via `api_mcp`)
|
| 199 |
+
- Additional MCP tools available at `/tools/mcp/`
|
| 200 |
+
- Regular FastAPI endpoints at their original paths
|
| 201 |
+
|
| 202 |
+
### Authentication and Middleware
|
| 203 |
+
|
| 204 |
+
When mounting MCP servers into FastAPI, you can leverage FastAPI's authentication and middleware:
|
| 205 |
+
|
| 206 |
+
```python
|
| 207 |
+
from fastapi import FastAPI, Depends, HTTPException
|
| 208 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
| 209 |
+
|
| 210 |
+
security = HTTPBearer()
|
| 211 |
+
|
| 212 |
+
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
|
| 213 |
+
if credentials.credentials != "secret-token":
|
| 214 |
+
raise HTTPException(status_code=401, detail="Invalid token")
|
| 215 |
+
return credentials
|
| 216 |
+
|
| 217 |
+
app = FastAPI()
|
| 218 |
+
|
| 219 |
+
# Mount MCP server with authentication
|
| 220 |
+
@app.get("/secure")
|
| 221 |
+
def secure_endpoint(auth=Depends(verify_token)):
|
| 222 |
+
return {"message": "Authenticated"}
|
| 223 |
+
|
| 224 |
+
# The mounted MCP server inherits the app's security
|
| 225 |
+
mcp_app = mcp.http_app()
|
| 226 |
+
app.mount("/mcp", mcp_app, lifespan=mcp_app.lifespan)
|
| 227 |
+
```
|
| 228 |
+
|
| 229 |
+
For more advanced ASGI integration patterns, see the [ASGI Integration guide](/integrations/asgi).
|
docs/{servers → integrations}/openapi.mdx
RENAMED
|
@@ -1,21 +1,25 @@
|
|
| 1 |
---
|
| 2 |
-
title: OpenAPI
|
| 3 |
-
sidebarTitle: OpenAPI
|
| 4 |
-
description: Generate MCP servers from OpenAPI
|
| 5 |
-
icon:
|
| 6 |
---
|
|
|
|
| 7 |
import { VersionBadge } from '/snippets/version-badge.mdx'
|
| 8 |
|
| 9 |
<VersionBadge version="2.0.0" />
|
| 10 |
|
| 11 |
-
FastMCP can automatically generate an MCP server from
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
-
##
|
| 14 |
|
| 15 |
-
To convert an OpenAPI specification to an MCP server,
|
| 16 |
|
| 17 |
-
|
| 18 |
-
```python {11-15}
|
| 19 |
import httpx
|
| 20 |
from fastmcp import FastMCP
|
| 21 |
|
|
@@ -36,8 +40,27 @@ if __name__ == "__main__":
|
|
| 36 |
mcp.run()
|
| 37 |
```
|
| 38 |
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
## Route Mapping
|
| 43 |
|
|
@@ -51,7 +74,7 @@ Each `RouteMap` specifies a combination of methods, patterns, and tags, as well
|
|
| 51 |
- **Pattern**: Regex pattern to match the route path (e.g. `r"^/users/.*"` or `r".*"` for all)
|
| 52 |
- **Tags**: A set of OpenAPI tags that must all be present. An empty set (`{}`) means no tag filtering, so the route matches regardless of its tags.
|
| 53 |
- **MCP type**: What MCP component type to create (`TOOL`, `RESOURCE`, `RESOURCE_TEMPLATE`, or `EXCLUDE`)
|
| 54 |
-
- **MCP tags** A set of custom tags to add to components created from matching routes
|
| 55 |
|
| 56 |
Here is FastMCP's default rule:
|
| 57 |
|
|
@@ -70,7 +93,7 @@ When creating your FastMCP server, you can customize routing behavior by providi
|
|
| 70 |
|
| 71 |
For example, prior to FastMCP 2.8.0, GET requests were automatically mapped to `Resource` and `ResourceTemplate` components based on whether they had path parameters. (This was changed solely for client compatibility reasons.) You can restore this behavior by providing custom route maps:
|
| 72 |
|
| 73 |
-
```python
|
| 74 |
from fastmcp import FastMCP
|
| 75 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 76 |
|
|
@@ -83,7 +106,8 @@ semantic_maps = [
|
|
| 83 |
]
|
| 84 |
|
| 85 |
mcp = FastMCP.from_openapi(
|
| 86 |
-
|
|
|
|
| 87 |
route_maps=semantic_maps,
|
| 88 |
)
|
| 89 |
```
|
|
@@ -97,9 +121,9 @@ from fastmcp import FastMCP
|
|
| 97 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 98 |
|
| 99 |
mcp = FastMCP.from_openapi(
|
| 100 |
-
|
|
|
|
| 101 |
route_maps=[
|
| 102 |
-
|
| 103 |
# Analytics `GET` endpoints are tools
|
| 104 |
RouteMap(
|
| 105 |
methods=["GET"],
|
|
@@ -132,12 +156,13 @@ To exclude routes from the MCP server, use a route map to assign them to `MCPTyp
|
|
| 132 |
|
| 133 |
You can use this to remove sensitive or internal routes by targeting them specifically:
|
| 134 |
|
| 135 |
-
```python
|
| 136 |
from fastmcp import FastMCP
|
| 137 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 138 |
|
| 139 |
mcp = FastMCP.from_openapi(
|
| 140 |
-
|
|
|
|
| 141 |
route_maps=[
|
| 142 |
RouteMap(pattern=r"^/admin/.*", mcp_type=MCPType.EXCLUDE),
|
| 143 |
RouteMap(tags={"internal"}, mcp_type=MCPType.EXCLUDE),
|
|
@@ -146,15 +171,17 @@ mcp = FastMCP.from_openapi(
|
|
| 146 |
```
|
| 147 |
|
| 148 |
Or you can use a catch-all rule to exclude everything that your maps don't handle explicitly:
|
| 149 |
-
|
|
|
|
| 150 |
from fastmcp import FastMCP
|
| 151 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 152 |
|
| 153 |
mcp = FastMCP.from_openapi(
|
| 154 |
-
|
|
|
|
| 155 |
route_maps=[
|
| 156 |
# custom mapping logic goes here
|
| 157 |
-
...
|
| 158 |
# exclude all remaining routes
|
| 159 |
RouteMap(mcp_type=MCPType.EXCLUDE),
|
| 160 |
],
|
|
@@ -165,7 +192,6 @@ mcp = FastMCP.from_openapi(
|
|
| 165 |
Using a catch-all exclusion rule will prevent the default route mappings from being applied, since it will match every remaining route. This is useful if you want to explicitly allow-list certain routes.
|
| 166 |
</Tip>
|
| 167 |
|
| 168 |
-
|
| 169 |
### Advanced Route Mapping
|
| 170 |
|
| 171 |
<VersionBadge version="2.5.0" />
|
|
@@ -178,7 +204,6 @@ In addition to more precise targeting of methods, patterns, and tags, this funct
|
|
| 178 |
The `route_map_fn` **is** called on routes that matched `MCPType.EXCLUDE` in your custom maps, giving you an opportunity to override the exclusion.
|
| 179 |
</Tip>
|
| 180 |
|
| 181 |
-
|
| 182 |
```python
|
| 183 |
from fastmcp import FastMCP
|
| 184 |
from fastmcp.server.openapi import RouteMap, MCPType, HTTPRoute
|
|
@@ -200,12 +225,40 @@ def custom_route_mapper(route: HTTPRoute, mcp_type: MCPType) -> MCPType | None:
|
|
| 200 |
return None
|
| 201 |
|
| 202 |
mcp = FastMCP.from_openapi(
|
| 203 |
-
|
|
|
|
| 204 |
route_map_fn=custom_route_mapper,
|
| 205 |
)
|
| 206 |
```
|
| 207 |
|
| 208 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
| 210 |
### Tags
|
| 211 |
|
|
@@ -217,12 +270,12 @@ FastMCP provides several ways to add tags to your MCP components, allowing you t
|
|
| 217 |
|
| 218 |
You can add custom tags to components created from specific routes using the `mcp_tags` parameter in `RouteMap`. These tags will be applied to all components created from routes that match that particular route map.
|
| 219 |
|
| 220 |
-
```python
|
| 221 |
-
from fastmcp import FastMCP
|
| 222 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 223 |
|
| 224 |
mcp = FastMCP.from_openapi(
|
| 225 |
-
|
|
|
|
| 226 |
route_maps=[
|
| 227 |
# Add custom tags to all POST endpoints
|
| 228 |
RouteMap(
|
|
@@ -253,59 +306,18 @@ mcp = FastMCP.from_openapi(
|
|
| 253 |
|
| 254 |
#### Global Tags
|
| 255 |
|
| 256 |
-
You can add tags to **all** components by providing a `tags` parameter when creating your
|
| 257 |
-
|
| 258 |
-
<CodeGroup>
|
| 259 |
-
```python {6} from_openapi()
|
| 260 |
-
from fastmcp import FastMCP
|
| 261 |
|
|
|
|
| 262 |
mcp = FastMCP.from_openapi(
|
| 263 |
openapi_spec=spec,
|
| 264 |
client=client,
|
| 265 |
tags={"api-v2", "production", "external"}
|
| 266 |
)
|
| 267 |
```
|
| 268 |
-
```python {5} from_fastapi()
|
| 269 |
-
from fastmcp import FastMCP
|
| 270 |
-
|
| 271 |
-
mcp = FastMCP.from_fastapi(
|
| 272 |
-
app=app,
|
| 273 |
-
tags={"internal-api", "microservice"}
|
| 274 |
-
)
|
| 275 |
-
```
|
| 276 |
-
</CodeGroup>
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
### Names
|
| 280 |
-
|
| 281 |
-
<VersionBadge version="2.5.0" />
|
| 282 |
-
|
| 283 |
-
FastMCP automatically generates names for MCP components based on the OpenAPI specification. By default, it uses the `operationId` from your OpenAPI spec, up to the first double underscore (`__`).
|
| 284 |
-
|
| 285 |
-
All component names are automatically:
|
| 286 |
-
- **Slugified**: Spaces and special characters are converted to underscores or removed
|
| 287 |
-
- **Truncated**: Limited to 56 characters maximum to ensure compatibility
|
| 288 |
-
- **Unique**: If multiple components have the same name, a number is automatically appended to make them unique
|
| 289 |
-
|
| 290 |
-
For more control over component names, you can provide an `mcp_names` dictionary that maps `operationId` values to your desired names. The `operationId` must be exactly as it appears in the OpenAPI spec. The provided name will always be slugified and truncated.
|
| 291 |
-
|
| 292 |
-
```python {5-9}
|
| 293 |
-
from fastmcp import FastMCP
|
| 294 |
-
|
| 295 |
-
mcp = FastMCP.from_openapi(
|
| 296 |
-
...
|
| 297 |
-
mcp_names={
|
| 298 |
-
"list_users__with_pagination": "user_list",
|
| 299 |
-
"create_user__admin_required": "create_user",
|
| 300 |
-
"get_user_details__admin_required": "user_detail",
|
| 301 |
-
}
|
| 302 |
-
)
|
| 303 |
-
```
|
| 304 |
-
|
| 305 |
-
Any `operationId` not found in `mcp_names` will use the default strategy (operationId up to the first `__`).
|
| 306 |
-
|
| 307 |
|
| 308 |
### Advanced Customization
|
|
|
|
| 309 |
<VersionBadge version="2.5.0" />
|
| 310 |
|
| 311 |
By default, FastMCP creates MCP components using a variety of metadata from the OpenAPI spec, such as incorporating the OpenAPI description into the MCP component description.
|
|
@@ -316,8 +328,7 @@ At times you may want to modify those MCP components in a variety of ways, such
|
|
| 316 |
Your `mcp_component_fn` is expected to modify the component in-place, not to return a new component. The result of the function is ignored.
|
| 317 |
</Tip>
|
| 318 |
|
| 319 |
-
```python
|
| 320 |
-
from fastmcp import FastMCP
|
| 321 |
from fastmcp.server.openapi import (
|
| 322 |
HTTPRoute,
|
| 323 |
OpenAPITool,
|
|
@@ -329,7 +340,6 @@ def customize_components(
|
|
| 329 |
route: HTTPRoute,
|
| 330 |
component: OpenAPITool | OpenAPIResource | OpenAPIResourceTemplate,
|
| 331 |
) -> None:
|
| 332 |
-
|
| 333 |
# Add custom tags to all components
|
| 334 |
component.tags.add("openapi")
|
| 335 |
|
|
@@ -342,10 +352,12 @@ def customize_components(
|
|
| 342 |
component.tags.add("data")
|
| 343 |
|
| 344 |
mcp = FastMCP.from_openapi(
|
| 345 |
-
|
|
|
|
| 346 |
mcp_component_fn=customize_components,
|
| 347 |
)
|
| 348 |
```
|
|
|
|
| 349 |
## Request Parameter Handling
|
| 350 |
|
| 351 |
FastMCP intelligently handles different types of parameters in OpenAPI requests:
|
|
@@ -401,118 +413,4 @@ FastMCP handles array parameters according to OpenAPI specifications:
|
|
| 401 |
|
| 402 |
### Headers
|
| 403 |
|
| 404 |
-
Header parameters are automatically converted to strings and included in the HTTP request.
|
| 405 |
-
|
| 406 |
-
## Auth
|
| 407 |
-
|
| 408 |
-
If your API requires authentication, configure it on the HTTP client before creating the MCP server:
|
| 409 |
-
|
| 410 |
-
```python
|
| 411 |
-
import httpx
|
| 412 |
-
from fastmcp import FastMCP
|
| 413 |
-
|
| 414 |
-
# Bearer token authentication
|
| 415 |
-
api_client = httpx.AsyncClient(
|
| 416 |
-
base_url="https://api.example.com",
|
| 417 |
-
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
| 418 |
-
)
|
| 419 |
-
|
| 420 |
-
# Create MCP server with authenticated client
|
| 421 |
-
mcp = FastMCP.from_openapi(..., client=api_client)
|
| 422 |
-
```
|
| 423 |
-
## Timeouts
|
| 424 |
-
|
| 425 |
-
Set a timeout for all API requests:
|
| 426 |
-
|
| 427 |
-
```python
|
| 428 |
-
mcp = FastMCP.from_openapi(
|
| 429 |
-
openapi_spec=spec,
|
| 430 |
-
client=api_client,
|
| 431 |
-
timeout=30.0 # 30 second timeout for all requests
|
| 432 |
-
)
|
| 433 |
-
```
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
## FastAPI Integration
|
| 437 |
-
|
| 438 |
-
<VersionBadge version="2.0.0" />
|
| 439 |
-
|
| 440 |
-
FastMCP can directly convert FastAPI applications into MCP servers by extracting their OpenAPI specifications:
|
| 441 |
-
|
| 442 |
-
<Tip>
|
| 443 |
-
FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration.
|
| 444 |
-
</Tip>
|
| 445 |
-
|
| 446 |
-
```python
|
| 447 |
-
from fastapi import FastAPI
|
| 448 |
-
from fastmcp import FastMCP
|
| 449 |
-
|
| 450 |
-
# Your FastAPI app
|
| 451 |
-
app = FastAPI(title="My API", version="1.0.0")
|
| 452 |
-
|
| 453 |
-
@app.get("/items", tags=["items"], operation_id="list_items")
|
| 454 |
-
def list_items():
|
| 455 |
-
return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}]
|
| 456 |
-
|
| 457 |
-
@app.get("/items/{item_id}", tags=["items", "detail"], operation_id="get_item")
|
| 458 |
-
def get_item(item_id: int):
|
| 459 |
-
return {"id": item_id, "name": f"Item {item_id}"}
|
| 460 |
-
|
| 461 |
-
@app.post("/items", tags=["items", "create"], operation_id="create_item")
|
| 462 |
-
def create_item(name: str):
|
| 463 |
-
return {"id": 3, "name": name}
|
| 464 |
-
|
| 465 |
-
# Convert FastAPI app to MCP server
|
| 466 |
-
mcp = FastMCP.from_fastapi(app=app)
|
| 467 |
-
|
| 468 |
-
if __name__ == "__main__":
|
| 469 |
-
mcp.run() # Run as MCP server
|
| 470 |
-
```
|
| 471 |
-
|
| 472 |
-
Note that operation ids are optional, but are used to create component names. You can also provide custom names, just like with OpenAPI specs.
|
| 473 |
-
|
| 474 |
-
<Warning>
|
| 475 |
-
FastMCP servers are not FastAPI apps, even when created from one. To learn how to deploy them as an ASGI app, see the [ASGI Integration](/deployment/asgi) documentation.
|
| 476 |
-
</Warning>
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
### FastAPI Configuration
|
| 481 |
-
|
| 482 |
-
All OpenAPI integration features work with FastAPI apps:
|
| 483 |
-
|
| 484 |
-
```python
|
| 485 |
-
from fastmcp.server.openapi import RouteMap, MCPType
|
| 486 |
-
|
| 487 |
-
# Custom route mapping with FastAPI
|
| 488 |
-
mcp = FastMCP.from_fastapi(
|
| 489 |
-
app=app,
|
| 490 |
-
name="My Custom Server",
|
| 491 |
-
timeout=5.0,
|
| 492 |
-
tags={"api-v1", "fastapi"}, # Global tags for all components
|
| 493 |
-
mcp_names={"operationId": "friendly_name"}, # Custom component names
|
| 494 |
-
route_maps=[
|
| 495 |
-
# Admin endpoints become tools with custom tags
|
| 496 |
-
RouteMap(
|
| 497 |
-
methods="*",
|
| 498 |
-
pattern=r"^/admin/.*",
|
| 499 |
-
mcp_type=MCPType.TOOL,
|
| 500 |
-
mcp_tags={"admin", "privileged"}
|
| 501 |
-
),
|
| 502 |
-
# Internal endpoints are excluded
|
| 503 |
-
RouteMap(methods="*", pattern=r".*", mcp_type=MCPType.EXCLUDE, tags={"internal"}),
|
| 504 |
-
],
|
| 505 |
-
route_map_fn=my_route_mapper,
|
| 506 |
-
mcp_component_fn=my_component_customizer,
|
| 507 |
-
mcp_names={
|
| 508 |
-
"get_user_details_users__user_id__get": "get_user_details",
|
| 509 |
-
}
|
| 510 |
-
)
|
| 511 |
-
```
|
| 512 |
-
|
| 513 |
-
### FastAPI Benefits
|
| 514 |
-
|
| 515 |
-
- **Zero code duplication**: Reuse existing FastAPI endpoints
|
| 516 |
-
- **Schema inheritance**: Pydantic models and validation are preserved
|
| 517 |
-
- **ASGI transport**: Direct in-memory communication (no HTTP overhead)
|
| 518 |
-
- **Full FastAPI features**: Dependencies, middleware, authentication all work
|
|
|
|
| 1 |
---
|
| 2 |
+
title: OpenAPI 🤝 FastMCP
|
| 3 |
+
sidebarTitle: OpenAPI
|
| 4 |
+
description: Generate MCP servers from any OpenAPI specification
|
| 5 |
+
icon: list-tree
|
| 6 |
---
|
| 7 |
+
|
| 8 |
import { VersionBadge } from '/snippets/version-badge.mdx'
|
| 9 |
|
| 10 |
<VersionBadge version="2.0.0" />
|
| 11 |
|
| 12 |
+
FastMCP can automatically generate an MCP server from any OpenAPI specification, allowing AI models to interact with existing APIs through the MCP protocol. Instead of manually creating tools and resources, you provide an OpenAPI spec and FastMCP intelligently converts API endpoints into the appropriate MCP components.
|
| 13 |
+
|
| 14 |
+
<Tip>
|
| 15 |
+
Generating MCP servers from OpenAPI is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted OpenAPI servers. This is especially true for complex APIs with many endpoints and parameters.
|
| 16 |
+
</Tip>
|
| 17 |
|
| 18 |
+
## Create a Server
|
| 19 |
|
| 20 |
+
To convert an OpenAPI specification to an MCP server, use the `FastMCP.from_openapi()` class method:
|
| 21 |
|
| 22 |
+
```python server.py
|
|
|
|
| 23 |
import httpx
|
| 24 |
from fastmcp import FastMCP
|
| 25 |
|
|
|
|
| 40 |
mcp.run()
|
| 41 |
```
|
| 42 |
|
| 43 |
+
### Authentication
|
| 44 |
+
|
| 45 |
+
If your API requires authentication, configure it on the HTTP client:
|
| 46 |
+
|
| 47 |
+
```python
|
| 48 |
+
import httpx
|
| 49 |
+
from fastmcp import FastMCP
|
| 50 |
+
|
| 51 |
+
# Bearer token authentication
|
| 52 |
+
api_client = httpx.AsyncClient(
|
| 53 |
+
base_url="https://api.example.com",
|
| 54 |
+
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
| 55 |
+
)
|
| 56 |
|
| 57 |
+
# Create MCP server with authenticated client
|
| 58 |
+
mcp = FastMCP.from_openapi(
|
| 59 |
+
openapi_spec=spec,
|
| 60 |
+
client=api_client,
|
| 61 |
+
timeout=30.0 # 30 second timeout for all requests
|
| 62 |
+
)
|
| 63 |
+
```
|
| 64 |
|
| 65 |
## Route Mapping
|
| 66 |
|
|
|
|
| 74 |
- **Pattern**: Regex pattern to match the route path (e.g. `r"^/users/.*"` or `r".*"` for all)
|
| 75 |
- **Tags**: A set of OpenAPI tags that must all be present. An empty set (`{}`) means no tag filtering, so the route matches regardless of its tags.
|
| 76 |
- **MCP type**: What MCP component type to create (`TOOL`, `RESOURCE`, `RESOURCE_TEMPLATE`, or `EXCLUDE`)
|
| 77 |
+
- **MCP tags**: A set of custom tags to add to components created from matching routes
|
| 78 |
|
| 79 |
Here is FastMCP's default rule:
|
| 80 |
|
|
|
|
| 93 |
|
| 94 |
For example, prior to FastMCP 2.8.0, GET requests were automatically mapped to `Resource` and `ResourceTemplate` components based on whether they had path parameters. (This was changed solely for client compatibility reasons.) You can restore this behavior by providing custom route maps:
|
| 95 |
|
| 96 |
+
```python
|
| 97 |
from fastmcp import FastMCP
|
| 98 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 99 |
|
|
|
|
| 106 |
]
|
| 107 |
|
| 108 |
mcp = FastMCP.from_openapi(
|
| 109 |
+
openapi_spec=spec,
|
| 110 |
+
client=client,
|
| 111 |
route_maps=semantic_maps,
|
| 112 |
)
|
| 113 |
```
|
|
|
|
| 121 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 122 |
|
| 123 |
mcp = FastMCP.from_openapi(
|
| 124 |
+
openapi_spec=spec,
|
| 125 |
+
client=client,
|
| 126 |
route_maps=[
|
|
|
|
| 127 |
# Analytics `GET` endpoints are tools
|
| 128 |
RouteMap(
|
| 129 |
methods=["GET"],
|
|
|
|
| 156 |
|
| 157 |
You can use this to remove sensitive or internal routes by targeting them specifically:
|
| 158 |
|
| 159 |
+
```python
|
| 160 |
from fastmcp import FastMCP
|
| 161 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 162 |
|
| 163 |
mcp = FastMCP.from_openapi(
|
| 164 |
+
openapi_spec=spec,
|
| 165 |
+
client=client,
|
| 166 |
route_maps=[
|
| 167 |
RouteMap(pattern=r"^/admin/.*", mcp_type=MCPType.EXCLUDE),
|
| 168 |
RouteMap(tags={"internal"}, mcp_type=MCPType.EXCLUDE),
|
|
|
|
| 171 |
```
|
| 172 |
|
| 173 |
Or you can use a catch-all rule to exclude everything that your maps don't handle explicitly:
|
| 174 |
+
|
| 175 |
+
```python
|
| 176 |
from fastmcp import FastMCP
|
| 177 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 178 |
|
| 179 |
mcp = FastMCP.from_openapi(
|
| 180 |
+
openapi_spec=spec,
|
| 181 |
+
client=client,
|
| 182 |
route_maps=[
|
| 183 |
# custom mapping logic goes here
|
| 184 |
+
# ... your specific route maps ...
|
| 185 |
# exclude all remaining routes
|
| 186 |
RouteMap(mcp_type=MCPType.EXCLUDE),
|
| 187 |
],
|
|
|
|
| 192 |
Using a catch-all exclusion rule will prevent the default route mappings from being applied, since it will match every remaining route. This is useful if you want to explicitly allow-list certain routes.
|
| 193 |
</Tip>
|
| 194 |
|
|
|
|
| 195 |
### Advanced Route Mapping
|
| 196 |
|
| 197 |
<VersionBadge version="2.5.0" />
|
|
|
|
| 204 |
The `route_map_fn` **is** called on routes that matched `MCPType.EXCLUDE` in your custom maps, giving you an opportunity to override the exclusion.
|
| 205 |
</Tip>
|
| 206 |
|
|
|
|
| 207 |
```python
|
| 208 |
from fastmcp import FastMCP
|
| 209 |
from fastmcp.server.openapi import RouteMap, MCPType, HTTPRoute
|
|
|
|
| 225 |
return None
|
| 226 |
|
| 227 |
mcp = FastMCP.from_openapi(
|
| 228 |
+
openapi_spec=spec,
|
| 229 |
+
client=client,
|
| 230 |
route_map_fn=custom_route_mapper,
|
| 231 |
)
|
| 232 |
```
|
| 233 |
|
| 234 |
+
## Customization
|
| 235 |
+
|
| 236 |
+
### Component Names
|
| 237 |
+
|
| 238 |
+
<VersionBadge version="2.5.0" />
|
| 239 |
+
|
| 240 |
+
FastMCP automatically generates names for MCP components based on the OpenAPI specification. By default, it uses the `operationId` from your OpenAPI spec, up to the first double underscore (`__`).
|
| 241 |
+
|
| 242 |
+
All component names are automatically:
|
| 243 |
+
- **Slugified**: Spaces and special characters are converted to underscores or removed
|
| 244 |
+
- **Truncated**: Limited to 56 characters maximum to ensure compatibility
|
| 245 |
+
- **Unique**: If multiple components have the same name, a number is automatically appended to make them unique
|
| 246 |
+
|
| 247 |
+
For more control over component names, you can provide an `mcp_names` dictionary that maps `operationId` values to your desired names. The `operationId` must be exactly as it appears in the OpenAPI spec. The provided name will always be slugified and truncated.
|
| 248 |
+
|
| 249 |
+
```python
|
| 250 |
+
mcp = FastMCP.from_openapi(
|
| 251 |
+
openapi_spec=spec,
|
| 252 |
+
client=client,
|
| 253 |
+
mcp_names={
|
| 254 |
+
"list_users__with_pagination": "user_list",
|
| 255 |
+
"create_user__admin_required": "create_user",
|
| 256 |
+
"get_user_details__admin_required": "user_detail",
|
| 257 |
+
}
|
| 258 |
+
)
|
| 259 |
+
```
|
| 260 |
+
|
| 261 |
+
Any `operationId` not found in `mcp_names` will use the default strategy (operationId up to the first `__`).
|
| 262 |
|
| 263 |
### Tags
|
| 264 |
|
|
|
|
| 270 |
|
| 271 |
You can add custom tags to components created from specific routes using the `mcp_tags` parameter in `RouteMap`. These tags will be applied to all components created from routes that match that particular route map.
|
| 272 |
|
| 273 |
+
```python
|
|
|
|
| 274 |
from fastmcp.server.openapi import RouteMap, MCPType
|
| 275 |
|
| 276 |
mcp = FastMCP.from_openapi(
|
| 277 |
+
openapi_spec=spec,
|
| 278 |
+
client=client,
|
| 279 |
route_maps=[
|
| 280 |
# Add custom tags to all POST endpoints
|
| 281 |
RouteMap(
|
|
|
|
| 306 |
|
| 307 |
#### Global Tags
|
| 308 |
|
| 309 |
+
You can add tags to **all** components by providing a `tags` parameter when creating your MCP server. These global tags will be applied to every component created from your OpenAPI specification.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
|
| 311 |
+
```python
|
| 312 |
mcp = FastMCP.from_openapi(
|
| 313 |
openapi_spec=spec,
|
| 314 |
client=client,
|
| 315 |
tags={"api-v2", "production", "external"}
|
| 316 |
)
|
| 317 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
|
| 319 |
### Advanced Customization
|
| 320 |
+
|
| 321 |
<VersionBadge version="2.5.0" />
|
| 322 |
|
| 323 |
By default, FastMCP creates MCP components using a variety of metadata from the OpenAPI spec, such as incorporating the OpenAPI description into the MCP component description.
|
|
|
|
| 328 |
Your `mcp_component_fn` is expected to modify the component in-place, not to return a new component. The result of the function is ignored.
|
| 329 |
</Tip>
|
| 330 |
|
| 331 |
+
```python
|
|
|
|
| 332 |
from fastmcp.server.openapi import (
|
| 333 |
HTTPRoute,
|
| 334 |
OpenAPITool,
|
|
|
|
| 340 |
route: HTTPRoute,
|
| 341 |
component: OpenAPITool | OpenAPIResource | OpenAPIResourceTemplate,
|
| 342 |
) -> None:
|
|
|
|
| 343 |
# Add custom tags to all components
|
| 344 |
component.tags.add("openapi")
|
| 345 |
|
|
|
|
| 352 |
component.tags.add("data")
|
| 353 |
|
| 354 |
mcp = FastMCP.from_openapi(
|
| 355 |
+
openapi_spec=spec,
|
| 356 |
+
client=client,
|
| 357 |
mcp_component_fn=customize_components,
|
| 358 |
)
|
| 359 |
```
|
| 360 |
+
|
| 361 |
## Request Parameter Handling
|
| 362 |
|
| 363 |
FastMCP intelligently handles different types of parameters in OpenAPI requests:
|
|
|
|
| 413 |
|
| 414 |
### Headers
|
| 415 |
|
| 416 |
+
Header parameters are automatically converted to strings and included in the HTTP request.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/{deployment/asgi.mdx → integrations/starlette.mdx}
RENAMED
|
@@ -1,27 +1,24 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
sidebarTitle:
|
| 4 |
-
description: Integrate FastMCP servers into
|
| 5 |
-
icon:
|
| 6 |
---
|
| 7 |
|
| 8 |
import { VersionBadge } from '/snippets/version-badge.mdx'
|
| 9 |
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
- Adding MCP functionality to an existing website or API
|
| 14 |
- Mounting MCP servers under specific URL paths
|
| 15 |
- Combining multiple services in a single application
|
| 16 |
- Leveraging existing authentication and middleware
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
## ASGI Server
|
| 21 |
-
|
| 22 |
-
FastMCP servers can be created as [Starlette](https://www.starlette.io/) ASGI apps for straightforward hosting or integration into existing applications.
|
| 23 |
|
| 24 |
-
|
| 25 |
|
| 26 |
<Tip>
|
| 27 |
The `http_app()` method is new in FastMCP 2.3.2. In older versions, use `sse_app()` for SSE transport or `streamable_http_app()` for Streamable HTTP transport.
|
|
@@ -43,87 +40,74 @@ http_app = mcp.http_app()
|
|
| 43 |
sse_app = mcp.http_app(transport="sse")
|
| 44 |
```
|
| 45 |
|
| 46 |
-
|
| 47 |
|
| 48 |
-
|
| 49 |
-
can access it from custom middleware or routes via `request.app.state.fastmcp_server`.
|
| 50 |
|
| 51 |
-
|
| 52 |
|
| 53 |
```python
|
| 54 |
-
#
|
| 55 |
http_app = mcp.http_app(path="/custom-mcp-path")
|
| 56 |
|
| 57 |
-
#
|
| 58 |
-
|
| 59 |
```
|
| 60 |
|
| 61 |
-
###
|
| 62 |
|
| 63 |
-
|
| 64 |
|
| 65 |
```python
|
| 66 |
from fastmcp import FastMCP
|
| 67 |
-
import
|
|
|
|
| 68 |
|
| 69 |
mcp = FastMCP("MyServer")
|
| 70 |
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
uvicorn.run(http_app, host="0.0.0.0", port=8000)
|
| 75 |
-
```
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
```bash
|
| 80 |
-
uvicorn path.to.your.app:http_app --host 0.0.0.0 --port 8000
|
| 81 |
```
|
| 82 |
|
| 83 |
-
###
|
| 84 |
-
|
| 85 |
-
<VersionBadge version="2.3.2" />
|
| 86 |
|
| 87 |
-
|
| 88 |
|
| 89 |
```python
|
| 90 |
from fastmcp import FastMCP
|
| 91 |
-
from starlette.
|
| 92 |
-
from starlette.
|
| 93 |
|
| 94 |
-
# Create your FastMCP server
|
| 95 |
mcp = FastMCP("MyServer")
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
CORSMiddleware,
|
| 101 |
-
allow_origins=["https://example.com", "https://app.example.com"],
|
| 102 |
-
allow_credentials=True,
|
| 103 |
-
allow_methods=["GET", "POST", "OPTIONS"],
|
| 104 |
-
allow_headers=["Content-Type", "Authorization"],
|
| 105 |
-
),
|
| 106 |
-
]
|
| 107 |
|
| 108 |
-
|
| 109 |
-
http_app = mcp.http_app(middleware=custom_middleware)
|
| 110 |
```
|
| 111 |
|
|
|
|
| 112 |
|
| 113 |
## Starlette Integration
|
| 114 |
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
You can mount your FastMCP server in another Starlette application:
|
| 118 |
|
| 119 |
```python
|
| 120 |
from fastmcp import FastMCP
|
| 121 |
from starlette.applications import Starlette
|
| 122 |
from starlette.routing import Mount
|
| 123 |
|
| 124 |
-
# Create your FastMCP server
|
| 125 |
mcp = FastMCP("MyServer")
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
# Create the ASGI app
|
| 128 |
mcp_app = mcp.http_app(path='/mcp')
|
| 129 |
|
|
@@ -145,7 +129,6 @@ For Streamable HTTP transport, you **must** pass the lifespan context from the F
|
|
| 145 |
|
| 146 |
### Nested Mounts
|
| 147 |
|
| 148 |
-
|
| 149 |
You can create complex routing structures by nesting mounts:
|
| 150 |
|
| 151 |
```python
|
|
@@ -153,7 +136,7 @@ from fastmcp import FastMCP
|
|
| 153 |
from starlette.applications import Starlette
|
| 154 |
from starlette.routing import Mount
|
| 155 |
|
| 156 |
-
# Create your FastMCP server
|
| 157 |
mcp = FastMCP("MyServer")
|
| 158 |
|
| 159 |
# Create the ASGI app
|
|
@@ -167,54 +150,64 @@ app = Starlette(
|
|
| 167 |
)
|
| 168 |
```
|
| 169 |
|
| 170 |
-
In this setup, the MCP server is accessible at the `/outer/inner/mcp/` path
|
| 171 |
|
| 172 |
-
|
| 173 |
-
For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the *outer* Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized.
|
| 174 |
-
</Warning>
|
| 175 |
-
## FastAPI Integration
|
| 176 |
|
| 177 |
-
<VersionBadge version="2.3.
|
| 178 |
|
| 179 |
-
|
| 180 |
|
| 181 |
```python
|
| 182 |
from fastmcp import FastMCP
|
| 183 |
-
from
|
| 184 |
-
from starlette.
|
| 185 |
|
| 186 |
-
# Create your FastMCP server
|
| 187 |
mcp = FastMCP("MyServer")
|
| 188 |
|
| 189 |
-
#
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
-
# Create
|
| 193 |
-
|
| 194 |
-
app.mount("/mcp-server", mcp_app)
|
| 195 |
```
|
| 196 |
|
| 197 |
-
|
| 198 |
|
| 199 |
-
|
| 200 |
-
For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting FastAPI app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized.
|
| 201 |
-
</Warning>
|
| 202 |
|
|
|
|
|
|
|
| 203 |
|
| 204 |
-
|
|
|
|
|
|
|
| 205 |
|
| 206 |
-
|
| 207 |
|
| 208 |
-
```
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
from starlette.responses import PlainTextResponse
|
| 212 |
|
| 213 |
-
|
| 214 |
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
|
| 220 |
-
These routes will be included in the FastMCP app when mounted in your web application.
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Starlette / ASGI 🤝 FastMCP
|
| 3 |
+
sidebarTitle: Starlette / ASGI
|
| 4 |
+
description: Integrate FastMCP servers into ASGI applications
|
| 5 |
+
icon: server
|
| 6 |
---
|
| 7 |
|
| 8 |
import { VersionBadge } from '/snippets/version-badge.mdx'
|
| 9 |
|
| 10 |
+
<VersionBadge version="2.3.1" />
|
| 11 |
|
| 12 |
+
FastMCP servers can be integrated into existing ASGI applications, allowing you to add MCP functionality to your web applications. This is useful for:
|
| 13 |
|
| 14 |
- Adding MCP functionality to an existing website or API
|
| 15 |
- Mounting MCP servers under specific URL paths
|
| 16 |
- Combining multiple services in a single application
|
| 17 |
- Leveraging existing authentication and middleware
|
| 18 |
|
| 19 |
+
## Basic Usage
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
+
To integrate a FastMCP server into an ASGI application, use the `http_app()` method to obtain a Starlette application instance:
|
| 22 |
|
| 23 |
<Tip>
|
| 24 |
The `http_app()` method is new in FastMCP 2.3.2. In older versions, use `sse_app()` for SSE transport or `streamable_http_app()` for Streamable HTTP transport.
|
|
|
|
| 40 |
sse_app = mcp.http_app(transport="sse")
|
| 41 |
```
|
| 42 |
|
| 43 |
+
The returned Starlette application can be integrated with other ASGI-compatible web frameworks. The MCP server's endpoint is mounted at `/mcp/` for Streamable HTTP transport and `/sse/` for SSE transport.
|
| 44 |
|
| 45 |
+
### Configuration Options
|
|
|
|
| 46 |
|
| 47 |
+
You can customize the endpoint path and access the FastMCP server instance:
|
| 48 |
|
| 49 |
```python
|
| 50 |
+
# Custom endpoint path
|
| 51 |
http_app = mcp.http_app(path="/custom-mcp-path")
|
| 52 |
|
| 53 |
+
# Access the FastMCP server from middleware/routes
|
| 54 |
+
# The server is available at: request.app.state.fastmcp_server
|
| 55 |
```
|
| 56 |
|
| 57 |
+
### Adding Custom Routes
|
| 58 |
|
| 59 |
+
You can add custom web routes directly to your FastMCP server using the `@custom_route` decorator:
|
| 60 |
|
| 61 |
```python
|
| 62 |
from fastmcp import FastMCP
|
| 63 |
+
from starlette.requests import Request
|
| 64 |
+
from starlette.responses import JSONResponse
|
| 65 |
|
| 66 |
mcp = FastMCP("MyServer")
|
| 67 |
|
| 68 |
+
@mcp.custom_route("/api/status", methods=["GET"])
|
| 69 |
+
async def get_status(request: Request):
|
| 70 |
+
return JSONResponse({"server": "running"})
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
http_app = mcp.http_app()
|
|
|
|
|
|
|
|
|
|
| 73 |
```
|
| 74 |
|
| 75 |
+
#### Health Check Endpoints
|
|
|
|
|
|
|
| 76 |
|
| 77 |
+
Health checks are commonly needed for monitoring and load balancing:
|
| 78 |
|
| 79 |
```python
|
| 80 |
from fastmcp import FastMCP
|
| 81 |
+
from starlette.requests import Request
|
| 82 |
+
from starlette.responses import JSONResponse
|
| 83 |
|
|
|
|
| 84 |
mcp = FastMCP("MyServer")
|
| 85 |
|
| 86 |
+
@mcp.custom_route("/health", methods=["GET"])
|
| 87 |
+
async def health_check(request: Request):
|
| 88 |
+
return JSONResponse({"status": "healthy"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
+
http_app = mcp.http_app()
|
|
|
|
| 91 |
```
|
| 92 |
|
| 93 |
+
The health endpoint will be available at `/health` alongside your MCP endpoint at `/mcp/`.
|
| 94 |
|
| 95 |
## Starlette Integration
|
| 96 |
|
| 97 |
+
Mount your FastMCP server in another Starlette application:
|
|
|
|
|
|
|
| 98 |
|
| 99 |
```python
|
| 100 |
from fastmcp import FastMCP
|
| 101 |
from starlette.applications import Starlette
|
| 102 |
from starlette.routing import Mount
|
| 103 |
|
| 104 |
+
# Create your FastMCP server
|
| 105 |
mcp = FastMCP("MyServer")
|
| 106 |
|
| 107 |
+
@mcp.tool
|
| 108 |
+
def analyze(data: str) -> dict:
|
| 109 |
+
return {"result": f"Analyzed: {data}"}
|
| 110 |
+
|
| 111 |
# Create the ASGI app
|
| 112 |
mcp_app = mcp.http_app(path='/mcp')
|
| 113 |
|
|
|
|
| 129 |
|
| 130 |
### Nested Mounts
|
| 131 |
|
|
|
|
| 132 |
You can create complex routing structures by nesting mounts:
|
| 133 |
|
| 134 |
```python
|
|
|
|
| 136 |
from starlette.applications import Starlette
|
| 137 |
from starlette.routing import Mount
|
| 138 |
|
| 139 |
+
# Create your FastMCP server
|
| 140 |
mcp = FastMCP("MyServer")
|
| 141 |
|
| 142 |
# Create the ASGI app
|
|
|
|
| 150 |
)
|
| 151 |
```
|
| 152 |
|
| 153 |
+
In this setup, the MCP server is accessible at the `/outer/inner/mcp/` path.
|
| 154 |
|
| 155 |
+
## Custom Middleware
|
|
|
|
|
|
|
|
|
|
| 156 |
|
| 157 |
+
<VersionBadge version="2.3.2" />
|
| 158 |
|
| 159 |
+
Add custom Starlette middleware to your FastMCP ASGI apps by passing a list of middleware instances:
|
| 160 |
|
| 161 |
```python
|
| 162 |
from fastmcp import FastMCP
|
| 163 |
+
from starlette.middleware import Middleware
|
| 164 |
+
from starlette.middleware.cors import CORSMiddleware
|
| 165 |
|
| 166 |
+
# Create your FastMCP server
|
| 167 |
mcp = FastMCP("MyServer")
|
| 168 |
|
| 169 |
+
# Define custom middleware
|
| 170 |
+
custom_middleware = [
|
| 171 |
+
Middleware(
|
| 172 |
+
CORSMiddleware,
|
| 173 |
+
allow_origins=["*"],
|
| 174 |
+
allow_methods=["*"],
|
| 175 |
+
allow_headers=["*"],
|
| 176 |
+
)
|
| 177 |
+
]
|
| 178 |
|
| 179 |
+
# Create ASGI app with middleware
|
| 180 |
+
http_app = mcp.http_app(custom_middleware=custom_middleware)
|
|
|
|
| 181 |
```
|
| 182 |
|
| 183 |
+
## Running the Server
|
| 184 |
|
| 185 |
+
To run your ASGI application, use an ASGI server like `uvicorn`:
|
|
|
|
|
|
|
| 186 |
|
| 187 |
+
```python
|
| 188 |
+
import uvicorn
|
| 189 |
|
| 190 |
+
if __name__ == "__main__":
|
| 191 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
| 192 |
+
```
|
| 193 |
|
| 194 |
+
Or from the command line:
|
| 195 |
|
| 196 |
+
```bash
|
| 197 |
+
uvicorn path.to.your.app:app --host 0.0.0.0 --port 8000
|
| 198 |
+
```
|
|
|
|
| 199 |
|
| 200 |
+
## Framework-Specific Integration
|
| 201 |
|
| 202 |
+
### FastAPI
|
| 203 |
+
|
| 204 |
+
For FastAPI-specific integration patterns including both mounting MCP servers into FastAPI apps and generating MCP servers from FastAPI apps, see the [FastAPI Integration guide](/integrations/fastapi).
|
| 205 |
+
|
| 206 |
+
### Other ASGI Frameworks
|
| 207 |
+
|
| 208 |
+
The patterns shown here work with any ASGI-compatible framework. The key requirements are:
|
| 209 |
+
|
| 210 |
+
1. Mount the FastMCP ASGI app at your desired path
|
| 211 |
+
2. Pass the lifespan context to your root application
|
| 212 |
+
3. Configure any necessary middleware or authentication
|
| 213 |
|
|
|
docs/servers/server.mdx
CHANGED
|
@@ -232,6 +232,28 @@ proxy = FastMCP.as_proxy(backend, name="ProxyServer")
|
|
| 232 |
# Now use the proxy like any FastMCP server
|
| 233 |
```
|
| 234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
## Server Configuration
|
| 236 |
|
| 237 |
Servers can be configured using a combination of initialization arguments, global settings, and transport-specific settings.
|
|
@@ -322,12 +344,12 @@ await mcp.run_async(
|
|
| 322 |
)
|
| 323 |
```
|
| 324 |
|
| 325 |
-
###
|
| 326 |
|
| 327 |
-
|
| 328 |
|
| 329 |
```bash
|
| 330 |
-
#
|
| 331 |
export FASTMCP_LOG_LEVEL=DEBUG
|
| 332 |
export FASTMCP_MASK_ERROR_DETAILS=True
|
| 333 |
export FASTMCP_RESOURCE_PREFIX_FORMAT=protocol
|
|
|
|
| 232 |
# Now use the proxy like any FastMCP server
|
| 233 |
```
|
| 234 |
|
| 235 |
+
## OpenAPI Integration
|
| 236 |
+
|
| 237 |
+
<VersionBadge version="2.0.0" />
|
| 238 |
+
|
| 239 |
+
FastMCP can automatically generate servers from OpenAPI specifications or existing FastAPI applications using `FastMCP.from_openapi()` and `FastMCP.from_fastapi()`. This allows you to instantly convert existing APIs into MCP servers without manual tool creation.
|
| 240 |
+
|
| 241 |
+
See the [FastAPI Integration](/integrations/fastapi) and [OpenAPI Integration](/integrations/openapi) guides for detailed examples and configuration options.
|
| 242 |
+
|
| 243 |
+
```python
|
| 244 |
+
import httpx
|
| 245 |
+
from fastmcp import FastMCP
|
| 246 |
+
|
| 247 |
+
# From OpenAPI spec
|
| 248 |
+
spec = httpx.get("https://api.example.com/openapi.json").json()
|
| 249 |
+
mcp = FastMCP.from_openapi(openapi_spec=spec, client=httpx.AsyncClient())
|
| 250 |
+
|
| 251 |
+
# From FastAPI app
|
| 252 |
+
from fastapi import FastAPI
|
| 253 |
+
app = FastAPI()
|
| 254 |
+
mcp = FastMCP.from_fastapi(app=app)
|
| 255 |
+
```
|
| 256 |
+
|
| 257 |
## Server Configuration
|
| 258 |
|
| 259 |
Servers can be configured using a combination of initialization arguments, global settings, and transport-specific settings.
|
|
|
|
| 344 |
)
|
| 345 |
```
|
| 346 |
|
| 347 |
+
### Setting Global Configuration
|
| 348 |
|
| 349 |
+
Global FastMCP settings can be configured via environment variables (prefixed with `FASTMCP_`):
|
| 350 |
|
| 351 |
```bash
|
| 352 |
+
# Configure global FastMCP behavior
|
| 353 |
export FASTMCP_LOG_LEVEL=DEBUG
|
| 354 |
export FASTMCP_MASK_ERROR_DETAILS=True
|
| 355 |
export FASTMCP_RESOURCE_PREFIX_FORMAT=protocol
|