# FastMCP OpenAPI Integration This document explains how FastMCP's OpenAPI integration works, what features are supported, and how to extend it. The OpenAPI functionality is split across two main files: - `server/openapi.py` - High-level FastMCP server implementation and MCP component creation - `utilities/openapi.py` - Low-level OpenAPI parsing and intermediate representation ## Architecture Overview ``` OpenAPI Spec → Parse → HTTPRoute IR → Create MCP Components → FastMCP Server ``` ### 1. Parsing Phase (`utilities/openapi.py`) OpenAPI specifications are parsed into an intermediate representation (IR) that normalizes differences between OpenAPI 3.0 and 3.1: - **Input**: Raw OpenAPI spec (dict) - **Output**: List of `HTTPRoute` objects with normalized parameter information - **Key Classes**: - `HTTPRoute` - Represents a single operation - `ParameterInfo` - Represents a parameter with location, style, explode, etc. - `RequestBodyInfo` - Represents request body information - `ResponseInfo` - Represents response information ### 2. Component Creation Phase (`server/openapi.py`) HTTPRoute objects are converted into FastMCP components based on route mapping rules: - **Tools** (`OpenAPITool`) - HTTP operations that can be called - **Resources** (`OpenAPIResource`) - HTTP endpoints that return data - **Resource Templates** (`OpenAPIResourceTemplate`) - Parameterized resources ## Parameter Handling FastMCP supports various OpenAPI parameter serialization styles and formats: ### Supported Parameter Locations - `query` - Query string parameters - `path` - Path parameters - `header` - HTTP headers - `cookie` - Cookie parameters (parsed but not used in requests) ### Supported Parameter Styles #### Query Parameters - **`form`** (default) - Standard query parameter format - `explode=true` (default): `?tags=red&tags=blue` - `explode=false`: `?tags=red,blue` - **`deepObject`** - Object parameters with bracket notation - `explode=true`: `?filter[name]=John&filter[age]=30` - `explode=false`: Falls back to JSON string (non-standard, logs warning) #### Path Parameters - **`simple`** (default) - Comma-separated for arrays: `/users/1,2,3` #### Header Parameters - **`simple`** (default) - Standard header format ### Parameter Type Support #### Arrays - String arrays with `explode=true/false` - Number arrays with `explode=true/false` - Boolean arrays with `explode=true/false` - Complex object arrays (basic support, may not handle all cases) #### Objects - Objects with `deepObject` style and `explode=true` - Objects with other styles fall back to JSON serialization #### Primitives - Strings, numbers, booleans - Enums - Default values ## Request Body Handling ### Supported Content Types - `application/json` - JSON request bodies ### Schema Support - Object schemas with properties - Array schemas - Primitive schemas - Schema references (`$ref` to local schemas only) - Required properties - Default values ## Response Handling ### Content Type Detection - `application/json` - Parsed as JSON - `text/*` - Returned as text - `application/xml` - Returned as text - Other types - Returned as binary ### Output Schema Generation - Success response schemas (200, 201, 202, 204) - Object response wrapping for MCP compliance - Schema compression (removes unused `$defs`) ## Route Mapping Routes are mapped to MCP component types using `RouteMap` configurations: ```python RouteMap( methods=["GET", "POST"], # HTTP methods to match pattern=r"/api/users/.*", # Regex pattern for path mcp_type=MCPType.RESOURCE_TEMPLATE, # Target component type tags={"user"}, # OpenAPI tags to match (AND condition) mcp_tags={"fastmcp-user"} # Tags to add to created components ) ``` ### Default Behavior - All routes become **Tools** by default - Use route maps to override specific patterns ### Component Types - `MCPType.TOOL` - Callable operations - `MCPType.RESOURCE` - Static data endpoints - `MCPType.RESOURCE_TEMPLATE` - Parameterized data endpoints - `MCPType.EXCLUDE` - Skip route entirely ## Known Limitations & Edge Cases ### Parameter Edge Cases 1. **Parameter Name Collisions** - When path/query parameters have same names as request body properties, non-body parameters get `__location` suffixes 2. **Complex Array Serialization** - Limited support for arrays containing objects 3. **Cookie Parameters** - Parsed but not used in requests 4. **Non-standard Combinations** - e.g., `deepObject` with `explode=false` ### Request Body Edge Cases 1. **Content Type Priority** - Only first available content type is used 2. **Nested Objects** - Deep nesting may not serialize correctly 3. **Binary Content** - No support for file uploads or binary data ### Response Edge Cases 1. **Multiple Content Types** - Only JSON-compatible types are used for output schemas 2. **Error Responses** - Not used for MCP output schema generation 3. **Response Headers** - Not captured or exposed ### Schema Edge Cases 1. **External References** - `$ref` to external files not supported 2. **Circular References** - May cause issues in schema processing 3. **Polymorphism** - `oneOf`/`anyOf`/`allOf` limited support ## Debugging Tips ### Common Issues 1. **"Unknown tool/resource"** - Check route mapping configuration 2. **Parameter not found** - Check for name collisions or incorrect style/explode 3. **Invalid request format** - Check parameter serialization and content types 4. **Schema validation errors** - Check for external refs or complex schemas ### Debugging Tools ```python # Parse routes to inspect intermediate representation routes = parse_openapi_to_http_routes(openapi_spec) for route in routes: print(f"{route.method} {route.path}") for param in route.parameters: print(f" {param.name} ({param.location}): style={param.style}, explode={param.explode}") # Check component creation server = FastMCP.from_openapi(openapi_spec, client) tools = await server.get_tools() print(f"Created {len(tools)} tools: {list(tools.keys())}") ``` ### Logging - Set `FASTMCP_LOG_LEVEL=DEBUG` to see detailed parameter processing - Look for warnings about non-standard parameter combinations - Check for schema parsing errors in logs ## Extension Points ### Adding New Parameter Styles 1. Add style handling in `utilities/openapi.py` - `ParameterInfo` class 2. Implement serialization logic in `server/openapi.py` - `OpenAPITool.run()` 3. Add tests for parsing and serialization ### Adding New Content Types 1. Extend request body handling in `OpenAPITool.run()` 2. Add response parsing logic for new types 3. Update content type priority in utilities ### Custom Route Mapping Use `route_map_fn` for complex routing logic: ```python def custom_mapper(route: HTTPRoute, current_type: MCPType) -> MCPType: if route.path.startswith("/admin"): return MCPType.EXCLUDE return current_type server = FastMCP.from_openapi(spec, client, route_map_fn=custom_mapper) ``` ## Testing Patterns ### Unit Tests - Test parameter parsing with various styles/explode combinations - Test route mapping with different patterns and tags - Test schema generation and compression ### Integration Tests - Mock HTTP client to verify actual request parameters - Test end-to-end component creation and execution - Test error handling and edge cases ### Example Test Pattern ```python async def test_parameter_style(): # 1. Create OpenAPI spec with specific parameter configuration spec = {"openapi": "3.1.0", ...} # 2. Parse and create components routes = parse_openapi_to_http_routes(spec) tool = OpenAPITool(mock_client, routes[0], ...) # 3. Execute and verify request parameters await tool.run({"param": "value"}) actual_params = mock_client.request.call_args.kwargs["params"] assert actual_params == expected_params ``` ## Testing OpenAPI functionality is tested across multiple files in `tests/server/openapi/`: - `test_basic_functionality.py` - Core component creation and execution - `test_explode_integration.py` - Parameter explode behavior - `test_deepobject_style.py` - DeepObject style parameter encoding - `test_parameter_collisions.py` - Parameter name collision handling - `test_openapi_path_parameters.py` - Path parameter serialization - `test_configuration.py` - Route mapping and MCP names - `test_description_propagation.py` - Schema and description handling When adding new OpenAPI features, create focused test files rather than adding to existing monolithic files. --- *This document should be updated when new OpenAPI features are added or when edge cases are discovered and addressed.*