Spaces:
Running
Running
| title: OpenAPI Integration | |
| sidebarTitle: OpenAPI | |
| description: Automatically create FastMCP servers from existing OpenAPI specifications. | |
| icon: code-branch | |
| If you have existing REST APIs documented with the OpenAPI Specification (OAS), FastMCP can automatically generate MCP tools, resources, and resource templates directly from that specification. This provides a quick way to make your existing HTTP APIs accessible to MCP clients and LLMs. | |
| FastMCP supports both OpenAPI 3.0 and 3.1 specifications for maximum compatibility with existing API definitions. | |
| ## The Goal: API -> MCP Server | |
| The core idea is to map OpenAPI paths and operations (like `GET /users/{id}` or `POST /orders`) to their corresponding MCP components: | |
| - `GET` requests often map to MCP **Resources** (for fetching single items) or **Resource Templates** (if the path has parameters). | |
| - `POST`, `PUT`, `PATCH`, `DELETE` requests typically map to MCP **Tools** (for actions that create or modify data). | |
| FastMCP automates this mapping process. | |
| ## Creating from OpenAPI Spec | |
| Use the `FastMCP.from_openapi()` class method. You need: | |
| 1. The OpenAPI specification as a Python dictionary. | |
| 2. An `httpx.AsyncClient` configured to make requests to the actual API backend. | |
| <CodeGroup> | |
| ```python server.py | |
| import asyncio | |
| import httpx | |
| from fastmcp import FastMCP | |
| # load the OpenAPI specification from the openapi_spec.py file | |
| petstore_spec = PETSTORE_SPEC | |
| # Client to communicate with the actual Pet Store API backend | |
| # The base_url should match the server URL in the OpenAPI spec | |
| http_client = httpx.AsyncClient(base_url="http://petstore.example.com/api") | |
| # Create the FastMCP server from the spec | |
| # This is an async class method | |
| async def create_openapi_server(): | |
| mcp_server = await FastMCP.from_openapi( | |
| openapi_spec=petstore_spec, | |
| client=http_client, | |
| name="PetStoreMCP" # Optional name for the MCP server | |
| ) | |
| return mcp_server | |
| async def run_server(): | |
| server = await create_openapi_server() | |
| print(f"Starting OpenAPI-based server '{server.name}'...") | |
| # List discovered components | |
| tools = await server.list_tools() | |
| resources = await server.list_resources() | |
| templates = await server.list_resource_templates() | |
| print("Discovered Tools:", [t.name for t in tools]) | |
| print("Discovered Resources:", [r.uri for r in resources]) # Should be empty if no parameterless GETs | |
| print("Discovered Templates:", [t.uriTemplate for t in templates]) | |
| # Run the server (e.g., via stdio) | |
| # server.run() | |
| if __name__ == "__main__": | |
| # Example: Create the server and print discovered components | |
| # Requires httpx: uv pip install httpx | |
| asyncio.run(run_server()) | |
| # Expected Output might include: | |
| # Discovered Tools: ['listPets', 'createPet'] | |
| # Discovered Resources: [] | |
| # Discovered Templates: ['resource://openapi/showPetById/{petId}'] | |
| ``` | |
| ```python openapi_spec.py | |
| # Example OpenAPI Specification (simplified Pet Store) | |
| PETSTORE_SPEC = { | |
| "openapi": "3.1.0", | |
| "info": {"title": "Simple Pet Store", "version": "1.0.0"}, | |
| "servers": [{"url": "http://petstore.example.com/api"}], # Base URL for API calls | |
| "paths": { | |
| "/pets": { | |
| "get": { | |
| "summary": "List all pets", | |
| "operationId": "listPets", | |
| "tags": ["pets"], | |
| "parameters": [{ # Query parameter -> Tool argument | |
| "name": "limit", "in": "query", "schema": {"type": "integer"} | |
| }], | |
| "responses": {"200": {"description": "A list of pets."}}, | |
| }, | |
| "post": { # POST -> Tool | |
| "summary": "Create a pet", | |
| "operationId": "createPet", | |
| "tags": ["pets"], | |
| "requestBody": { # Request body -> Tool arguments | |
| "required": True, | |
| "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PetInput"}}} | |
| }, | |
| "responses": {"201": {"description": "Pet created."}}, | |
| }, | |
| }, | |
| "/pets/{petId}": { # Path parameter -> Resource Template | |
| "get": { # GET with path param -> Resource Template / FunctionResource | |
| "summary": "Info for a specific pet", | |
| "operationId": "showPetById", | |
| "tags": ["pets"], | |
| "parameters": [{ # Path parameter -> Template function argument | |
| "name": "petId", "in": "path", "required": True, "schema": {"type": "string"} | |
| }], | |
| "responses": {"200": {"description": "Information about the pet."}}, | |
| }, | |
| }, | |
| }, | |
| "components": { | |
| "schemas": { | |
| "PetInput": {"type": "object", "properties": {"name": {"type": "string"}, "tag": {"type": "string"}}}, | |
| } | |
| } | |
| } | |
| ``` | |
| </CodeGroup> | |
| ### How it Works Internally | |
| 1. **Parsing**: `from_openapi` parses the spec using utilities that leverage `openapi-pydantic`. It extracts paths, operations, parameters, request bodies, and responses. | |
| 2. **Mapping**: It applies mapping rules (see below) to decide whether each OpenAPI operation (`GET /pets`, `POST /pets`, `GET /pets/{petId}`) becomes an MCP `Tool`, `Resource`, or `ResourceTemplate`. | |
| 3. **Component Creation**: It creates specialized internal components (`OpenAPITool`, `OpenAPIResource`, `OpenAPIResourceTemplate`). | |
| 4. **HTTP Execution**: When an MCP client calls a tool or reads a resource from this server: | |
| * The corresponding OpenAPI component constructs an HTTP request based on the OpenAPI definition and the arguments provided by the MCP client. | |
| * It uses the provided `httpx.AsyncClient` to send the request to the backend API. | |
| * It processes the HTTP response and returns it to the MCP client in the appropriate MCP format. | |
| 5. **Schema Generation**: The schemas for MCP tools are derived by combining OpenAPI parameters (path, query, header) and request body schemas. Resource template function arguments are derived from path parameters. | |
| 6. **Descriptions**: Tool/Resource descriptions are enhanced with information from OpenAPI responses to give the LLM more context about potential outcomes. | |
| ### Default Mapping Rules | |
| FastMCP uses the following default rules to map OpenAPI operations: | |
| - `GET` operation with path parameters (e.g., `/users/{id}`) -> **`ResourceTemplate`** | |
| - `GET` operation without path parameters (e.g., `/users`) -> **`Resource`** | |
| - `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `HEAD` -> **`Tool`** | |
| ### Customize Route Mapping | |
| You can customize the mapping rules by providing a list of `RouteMap` objects directly to `FastMCP.from_openapi()` using the `route_maps` parameter: | |
| ```python | |
| from fastmcp.server.openapi import RouteMap, RouteType | |
| from fastmcp import FastMCP | |
| # Custom mapping: Treat GET /admin/stats as a Tool, not a Resource | |
| custom_maps = [ | |
| RouteMap(methods=["GET"], pattern=r"^/admin/stats$", route_type=RouteType.TOOL) | |
| ] | |
| async def create_server_with_custom_mapping(): | |
| mcp_server = await FastMCP.from_openapi( | |
| openapi_spec=petstore_spec, | |
| client=http_client, | |
| name="PetStoreMCP", | |
| route_maps=custom_maps # Pass custom mapping rules | |
| ) | |
| return mcp_server | |
| ``` | |
| Each `RouteMap` maps one or more HTTP methods and a regular expression pattern for the route path to an MCP `RouteType`. Route maps are processed in order, and the first match wins. | |
| All parameters passed to `FastMCP.from_openapi()` will be forwarded to the underlying `FastMCPOpenAPI` constructor, so you can customize any aspect of the OpenAPI integration directly through this method call. | |