mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-26 15:34:18 +02:00
Add support for RouteMap tags, update docs
This commit is contained in:
parent
702412e28b
commit
6cac09cf2a
9 changed files with 585 additions and 931 deletions
|
|
@ -8,19 +8,18 @@ import { VersionBadge } from '/snippets/version-badge.mdx'
|
|||
|
||||
<VersionBadge version="2.0.0" />
|
||||
|
||||
<Note>
|
||||
**Documentation Moved**: The comprehensive FastAPI integration documentation has been moved to the [OpenAPI Integration](/patterns/openapi#fastapi-integration) page, where it's covered alongside all other OpenAPI features including route mapping and tags support.
|
||||
</Note>
|
||||
|
||||
FastMCP can automatically convert FastAPI applications into MCP servers.
|
||||
## Quick Start
|
||||
|
||||
<Tip>
|
||||
FastMCP does *not* include FastAPI as a dependency; you must install it separately to run these examples.
|
||||
</Tip>
|
||||
FastMCP can automatically convert FastAPI applications into MCP servers:
|
||||
|
||||
|
||||
```python {2, 22, 25}
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastmcp import FastMCP
|
||||
|
||||
|
||||
# A FastAPI app
|
||||
app = FastAPI()
|
||||
|
||||
|
|
@ -36,7 +35,6 @@ def get_item(item_id: int):
|
|||
def create_item(name: str):
|
||||
return {"id": 3, "name": name}
|
||||
|
||||
|
||||
# Create an MCP server from your FastAPI app
|
||||
mcp = FastMCP.from_fastapi(app=app)
|
||||
|
||||
|
|
@ -44,101 +42,6 @@ if __name__ == "__main__":
|
|||
mcp.run() # Start the MCP server
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Timeout
|
||||
|
||||
You can set a timeout for all API requests:
|
||||
|
||||
```python
|
||||
# Set a 5 second timeout for all requests
|
||||
mcp = FastMCP.from_fastapi(app=app, timeout=5.0)
|
||||
```
|
||||
|
||||
This timeout is applied to all requests made by tools, resources, and resource templates.
|
||||
|
||||
## Route Mapping
|
||||
|
||||
By default, FastMCP will map FastAPI routes to MCP components according to the following rules:
|
||||
|
||||
| FastAPI Route Type | FastAPI Example | MCP Component | Notes |
|
||||
|--------------------|--------------|---------|-------|
|
||||
| GET without path params | `@app.get("/stats")` | Resource | Simple resources for fetching data |
|
||||
| GET with path params | `@app.get("/users/{id}")` | Resource Template | Path parameters become template parameters |
|
||||
| POST, PUT, DELETE, etc. | `@app.post("/users")` | Tool | Operations that modify data |
|
||||
|
||||
For more details on route mapping or custom mapping rules, see the [OpenAPI integration documentation](/patterns/openapi#route-mapping); FastMCP uses the same mapping rules for both FastAPI and OpenAPI integrations.
|
||||
|
||||
## Complete Example
|
||||
|
||||
Here's a more detailed example with a data model:
|
||||
|
||||
```python [expandable]
|
||||
import asyncio
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from fastmcp import FastMCP, Client
|
||||
|
||||
# Define your Pydantic model
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
|
||||
# Create your FastAPI app
|
||||
app = FastAPI()
|
||||
items = {} # In-memory database
|
||||
|
||||
@app.get("/items")
|
||||
def list_items():
|
||||
"""List all items"""
|
||||
return list(items.values())
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: int):
|
||||
"""Get item by ID"""
|
||||
if item_id not in items:
|
||||
raise HTTPException(404, "Item not found")
|
||||
return items[item_id]
|
||||
|
||||
@app.post("/items")
|
||||
def create_item(item: Item):
|
||||
"""Create a new item"""
|
||||
item_id = len(items) + 1
|
||||
items[item_id] = {"id": item_id, **item.model_dump()}
|
||||
return items[item_id]
|
||||
|
||||
# Test your MCP server with a client
|
||||
async def check_mcp(mcp: FastMCP):
|
||||
# List the components that were created
|
||||
tools = await mcp.get_tools()
|
||||
resources = await mcp.get_resources()
|
||||
templates = await mcp.get_resource_templates()
|
||||
|
||||
print(
|
||||
f"{len(tools)} Tool(s): {', '.join([t.name for t in tools.values()])}"
|
||||
)
|
||||
print(
|
||||
f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}"
|
||||
)
|
||||
print(
|
||||
f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}"
|
||||
)
|
||||
|
||||
return mcp
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create MCP server from FastAPI app
|
||||
mcp = FastMCP.from_fastapi(app=app)
|
||||
|
||||
asyncio.run(check_mcp(mcp))
|
||||
|
||||
# In a real scenario, you would run the server:
|
||||
mcp.run()
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Leverage existing FastAPI apps** - No need to rewrite your API logic
|
||||
- **Schema reuse** - FastAPI's Pydantic models and validation are inherited
|
||||
- **Full feature support** - Works with FastAPI's authentication, dependencies, etc.
|
||||
- **ASGI transport** - Direct communication without additional HTTP overhead
|
||||
<Tip>
|
||||
For complete documentation including tag-based routing, route mapping configuration, timeout settings, authentication examples, and advanced configuration options, see the comprehensive [OpenAPI Integration documentation](/patterns/openapi#fastapi-integration).
|
||||
</Tip>
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
---
|
||||
title: OpenAPI Integration
|
||||
sidebarTitle: OpenAPI
|
||||
description: Generate MCP servers from OpenAPI specs
|
||||
icon: code-branch
|
||||
---
|
||||
import { VersionBadge } from '/snippets/version-badge.mdx'
|
||||
|
||||
<VersionBadge version="2.0.0" />
|
||||
|
||||
FastMCP can automatically generate an MCP server from an OpenAPI specification. Users only need to provide an OpenAPI specification (3.0 or 3.1) and an API client.
|
||||
|
||||
```python
|
||||
import httpx
|
||||
from fastmcp import FastMCP
|
||||
|
||||
# Create a client for your API
|
||||
api_client = httpx.AsyncClient(base_url="https://api.example.com")
|
||||
|
||||
# Load your OpenAPI spec
|
||||
spec = {...}
|
||||
|
||||
# Create an MCP server from your OpenAPI spec
|
||||
mcp = FastMCP.from_openapi(openapi_spec=spec, client=api_client)
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Timeout
|
||||
|
||||
You can set a timeout for all requests by providing a `timeout` parameter (in seconds):
|
||||
|
||||
```python
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
timeout=30.0 # 30 second timeout
|
||||
)
|
||||
```
|
||||
|
||||
## Route Mapping
|
||||
|
||||
<VersionBadge version="2.5.0" />
|
||||
|
||||
By default, OpenAPI routes are mapped to MCP components based on these rules:
|
||||
|
||||
| OpenAPI Route | Example |MCP Component | Notes |
|
||||
|- | - | - | - |
|
||||
| `GET` without path params | `GET /stats` | Resource | Simple resources for fetching data |
|
||||
| `GET` with path params | `GET /users/{id}` | Resource Template | Path parameters become template parameters |
|
||||
| `POST`, `PUT`, `PATCH`, `DELETE`, etc. | `POST /users` | Tool | Operations that modify data |
|
||||
|
||||
Internally, FastMCP uses a priority-ordered set of `RouteMap` objects to determine the component type. Route maps indicate that a specific HTTP method (or methods) and path pattern should be treated as a specific component type. This is the default set of route maps:
|
||||
|
||||
```python
|
||||
# Simplified version of the actual mapping rules
|
||||
DEFAULT_ROUTE_MAPPINGS = [
|
||||
# GET with path parameters -> ResourceTemplate
|
||||
RouteMap(
|
||||
methods=["GET"],
|
||||
pattern=r".*\{.*\}.*",
|
||||
mcp_type=MCPType.RESOURCE_TEMPLATE,
|
||||
),
|
||||
|
||||
# GET without path parameters -> Resource
|
||||
RouteMap(
|
||||
methods=["GET"],
|
||||
pattern=r".*",
|
||||
mcp_type=MCPType.RESOURCE,
|
||||
),
|
||||
|
||||
# All other methods -> Tool
|
||||
ALL_TOOLS(),
|
||||
]
|
||||
```
|
||||
|
||||
#### Custom Route Maps
|
||||
|
||||
Users can add custom route maps to override the default mapping behavior. User-supplied route maps are always applied first, before the default route maps.
|
||||
|
||||
```python
|
||||
from fastmcp.server.openapi import RouteMap, MCPType
|
||||
|
||||
# Custom mapping rules
|
||||
custom_maps = [
|
||||
# Force all analytics endpoints to be Tools
|
||||
RouteMap(methods=["GET"],
|
||||
pattern=r"^/analytics/.*",
|
||||
mcp_type=MCPType.TOOL)
|
||||
]
|
||||
|
||||
# Apply custom mappings
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=custom_maps
|
||||
)
|
||||
```
|
||||
|
||||
<Info>
|
||||
For backward compatibility, FastMCP still supports the `route_type` parameter and `RouteType` enum, but they are deprecated and will be removed in a future version. You will see deprecation warnings if you use them.
|
||||
</Info>
|
||||
|
||||
#### All Routes as Tools
|
||||
|
||||
When building AI agent backends, it's often useful to treat all routes as callable tools regardless of their HTTP method. You can use the `ALL_TOOLS()` shortcut or create a custom route map:
|
||||
|
||||
```python
|
||||
# Make all endpoints tools using the shortcut
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=[ALL_TOOLS()]
|
||||
)
|
||||
|
||||
# Same effect using a custom route map
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=[
|
||||
RouteMap(methods="*", pattern=r".*", mcp_type=MCPType.TOOL)
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
#### Excluding Routes
|
||||
|
||||
If you want to exclude certain routes from being converted to MCP components, you can map them to `MCPType.EXCLUDE`. This is useful for endpoints that should not be accessible to the agent.
|
||||
|
||||
```python
|
||||
from fastmcp.server.openapi import RouteMap, MCPType
|
||||
|
||||
# Custom mapping rules to exclude specific routes
|
||||
custom_maps = [
|
||||
# Exclude all admin endpoints
|
||||
RouteMap(
|
||||
methods="*",
|
||||
pattern=r"^/admin/.*",
|
||||
mcp_type=MCPType.EXCLUDE
|
||||
),
|
||||
# Exclude analytics GET endpoints
|
||||
RouteMap(
|
||||
methods=["GET"],
|
||||
pattern=r"^/analytics/.*",
|
||||
mcp_type=MCPType.EXCLUDE
|
||||
)
|
||||
]
|
||||
|
||||
# Apply custom mappings
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=custom_maps
|
||||
)
|
||||
```
|
||||
|
||||
When a route is mapped to `MCPType.EXCLUDE`, FastMCP will log its presence but won't create any MCP component for it, effectively making it invisible to clients and agents using the MCP server.
|
||||
|
||||
You can customize this behavior by providing a list of `RouteMap` objects:
|
||||
|
||||
```python
|
||||
from fastmcp.server.openapi import FastMCPOpenAPI, RouteMap, MCPType
|
||||
|
||||
# Custom route mappings
|
||||
custom_mappings = [
|
||||
# Convert all user-related routes to tools
|
||||
RouteMap(
|
||||
methods=["GET", "POST", "PUT", "DELETE"],
|
||||
pattern=r"^/users.*",
|
||||
mcp_type=MCPType.TOOL
|
||||
),
|
||||
# Exclude analytics routes
|
||||
RouteMap(
|
||||
methods=["*"], # All methods
|
||||
pattern=r"^/analytics.*",
|
||||
mcp_type=MCPType.EXCLUDE
|
||||
),
|
||||
]
|
||||
|
||||
# Create server with custom mappings
|
||||
mcp = FastMCPOpenAPI(
|
||||
openapi_spec=spec,
|
||||
client=httpx.AsyncClient(),
|
||||
route_maps=custom_mappings,
|
||||
)
|
||||
```
|
||||
|
||||
#### Route Map Shortcuts
|
||||
|
||||
|
||||
FastMCP provides several shortcut functions to create common route maps more easily:
|
||||
|
||||
```python
|
||||
from fastmcp.server.openapi import (
|
||||
ALL_TOOLS,
|
||||
EXCLUDE_ALL,
|
||||
EXCLUDE_PATTERN,
|
||||
PATTERN_AS_TOOLS,
|
||||
)
|
||||
|
||||
# Create an MCP server with custom route maps using shortcuts
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=[
|
||||
# First exclude all admin endpoints
|
||||
EXCLUDE_PATTERN(r"^/admin/.*"),
|
||||
|
||||
# Make all /api/v1 endpoints tools
|
||||
PATTERN_AS_TOOLS(r"^/api/v1/.*"),
|
||||
|
||||
# Make all remaining routes tools
|
||||
ALL_TOOLS(),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Available shortcuts:
|
||||
|
||||
| Shortcut Function | Description |
|
||||
|------------------|-------------|
|
||||
| `ALL_TOOLS()` | Converts all matching routes to tools |
|
||||
| `EXCLUDE_ALL()` | Excludes all matching routes from being converted to any component |
|
||||
| `PATTERN_AS_TOOLS(pattern)` | Converts routes matching a specific pattern to tools |
|
||||
| `EXCLUDE_PATTERN(pattern)` | Excludes routes matching a specific pattern |
|
||||
|
||||
These shortcuts are particularly useful for:
|
||||
|
||||
1. Converting all remaining unmatched routes to tools (use `ALL_TOOLS()`)
|
||||
2. Excluding whole sections of your API (use `EXCLUDE_PATTERN("/path/.*")`)
|
||||
3. Converting routes matching specific patterns to tools (use `PATTERN_AS_TOOLS("/path/.*")`)
|
||||
|
||||
<Tip>
|
||||
You can use `EXCLUDE_ALL()` as the last entry in your custom route maps to completely ignore the default route maps. Since custom route maps are applied first and default maps are appended afterward, having `EXCLUDE_ALL()` at the end of your custom maps will match any routes that your earlier custom rules didn't match, preventing the default maps from having any effect.
|
||||
|
||||
```python
|
||||
# Create server that only uses custom route maps, ignoring defaults
|
||||
mcp = FastMCP.from_openapi(
|
||||
openapi_spec=spec,
|
||||
client=api_client,
|
||||
route_maps=[
|
||||
# Routes to keep as tools
|
||||
PATTERN_AS_TOOLS(r"^/api/v1/.*"),
|
||||
|
||||
# Exclude everything else (ignores default route maps)
|
||||
EXCLUDE_ALL(),
|
||||
]
|
||||
)
|
||||
```
|
||||
</Tip>
|
||||
|
||||
## How It Works
|
||||
|
||||
1. FastMCP parses your OpenAPI spec to extract routes and schemas
|
||||
2. It applies mapping rules to categorize each route
|
||||
3. When an MCP client calls a tool or accesses a resource:
|
||||
- FastMCP constructs an HTTP request based on the OpenAPI definition
|
||||
- It sends the request through the provided httpx client
|
||||
- It translates the HTTP response to the appropriate MCP format
|
||||
|
||||
### Request Parameter Handling
|
||||
|
||||
FastMCP carefully handles different types of parameters in OpenAPI requests:
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
By default, FastMCP will only include query parameters that have non-empty values. Parameters with `None` values or empty strings (`""`) are automatically filtered out of requests. This ensures that API servers don't receive unnecessary empty parameters that might cause issues.
|
||||
|
||||
For example, if you call a tool with these parameters:
|
||||
```python
|
||||
await client.call_tool("search_products", {
|
||||
"category": "electronics", # Will be included
|
||||
"min_price": 100, # Will be included
|
||||
"max_price": None, # Will be excluded
|
||||
"brand": "", # Will be excluded
|
||||
})
|
||||
```
|
||||
|
||||
The resulting HTTP request will only include `category=electronics&min_price=100`.
|
||||
|
||||
#### Path Parameters
|
||||
|
||||
For path parameters, which are typically required by REST APIs, FastMCP filters out `None` values and checks that all required path parameters are provided. If a required path parameter is missing or `None`, an error will be raised.
|
||||
|
||||
```python
|
||||
# This will work
|
||||
await client.call_tool("get_product", {"product_id": 123})
|
||||
|
||||
# This will raise ValueError: "Missing required path parameters: {'product_id'}"
|
||||
await client.call_tool("get_product", {"product_id": None})
|
||||
```
|
||||
|
||||
## Example: Custom Authentication
|
||||
|
||||
If your API requires authentication, you can set headers on the client:
|
||||
|
||||
```python
|
||||
import httpx
|
||||
from fastmcp import FastMCP
|
||||
|
||||
# Create a client with authentication
|
||||
api_client = httpx.AsyncClient(
|
||||
base_url="https://api.example.com",
|
||||
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
||||
)
|
||||
|
||||
# Create an MCP server from your OpenAPI spec
|
||||
mcp = FastMCP.from_openapi(openapi_spec=spec, client=api_client)
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue