--- title: OpenAPI Integration sidebarTitle: OpenAPI description: Generate MCP servers from OpenAPI specs icon: code-branch --- import { VersionBadge } from '/snippets/version-badge.mdx' 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 API requests: ```python # Set a 5 second timeout for all requests mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, timeout=5.0 ) ``` This timeout is applied to all requests made by tools, resources, and resource templates. ## Route Mapping 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 = await FastMCP.from_openapi( openapi_spec=spec, client=api_client, route_maps=custom_maps ) ``` 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. ### 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_routes_as_tools` parameter to automatically map every route to a Tool: ```python # Make all endpoints tools, regardless of HTTP method mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, all_routes_as_tools=True ) ``` This is equivalent to defining a single route map that matches all routes: ```python # Same effect as all_routes_as_tools=True mcp = FastMCP.from_openapi( openapi_spec=spec, client=api_client, route_maps=[ RouteMap(methods="*", pattern=r".*", mcp_type=MCPType.TOOL) ] ) ``` Note that `all_routes_as_tools` and `route_maps` cannot be used together - if you need more complex mapping rules, use `route_maps` instead. ### 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. ## 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}) ``` ## Complete Example ```python [expandable] import asyncio import httpx from fastmcp import FastMCP # Sample OpenAPI spec for a Pet Store API petstore_spec = { "openapi": "3.0.0", "info": { "title": "Pet Store API", "version": "1.0.0", "description": "A sample API for managing pets", }, "paths": { "/pets": { "get": { "operationId": "listPets", "summary": "List all pets", "responses": {"200": {"description": "A list of pets"}}, }, "post": { "operationId": "createPet", "summary": "Create a new pet", "responses": {"201": {"description": "Pet created successfully"}}, }, }, "/pets/{petId}": { "get": { "operationId": "getPet", "summary": "Get a pet by ID", "parameters": [ { "name": "petId", "in": "path", "required": True, "schema": {"type": "string"}, } ], "responses": { "200": {"description": "Pet details"}, "404": {"description": "Pet not found"}, }, } }, }, } async def check_mcp(mcp: FastMCP): # List what components 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()])}" ) # Should include createPet print( f"{len(resources)} Resource(s): {', '.join([r.name for r in resources.values()])}" ) # Should include listPets print( f"{len(templates)} Resource Template(s): {', '.join([t.name for t in templates.values()])}" ) # Should include getPet return mcp if __name__ == "__main__": # Client for the Pet Store API client = httpx.AsyncClient(base_url="https://petstore.example.com/api") # Create the MCP server mcp = FastMCP.from_openapi( openapi_spec=petstore_spec, client=client, name="PetStore" ) asyncio.run(check_mcp(mcp)) # Start the MCP server mcp.run() ``` ### 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/.*")`) The `all_routes_as_tools=True` parameter is equivalent to using just `[ALL_TOOLS()]` as your route maps. 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(), ] ) ```