---
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 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".*\{.*\}.*", 
        route_type=RouteType.RESOURCE_TEMPLATE,
    ),
    
    # GET without path parameters -> Resource
    RouteMap(
        methods=["GET"], 
        pattern=r".*", 
        route_type=RouteType.RESOURCE,
    ),
    
    # All other methods -> Tool
    RouteMap(
        methods="*",
        pattern=r".*", 
        route_type=RouteType.TOOL,
    ),
]
```
### 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, RouteType

# Custom mapping rules
custom_maps = [
    # Force all analytics endpoints to be Tools
    RouteMap(methods=["GET"], 
             pattern=r"^/analytics/.*", 
             route_type=RouteType.TOOL)
]

# Apply custom mappings
mcp = await FastMCP.from_openapi(
    openapi_spec=spec,
    client=api_client,
    route_maps=custom_maps
)
```


### 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".*", route_type=RouteType.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.

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

