fastmcp/docs/patterns/openapi.mdx
2025-05-22 21:11:46 -04:00

312 lines
9.3 KiB
Text

---
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)
```