Skip to content

Latest commit

 

History

History
246 lines (186 loc) · 8.51 KB

File metadata and controls

246 lines (186 loc) · 8.51 KB

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:

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

# 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:

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

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.