FlashMCP 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.
import httpxfrom FlashMCP import FlashMCP# Create a client for your APIapi_client = httpx.AsyncClient(base_url="https://api.example.com")# Load your OpenAPI specspec = {...} # Create an MCP server from your OpenAPI specmcp = FlashMCP.from_openapi(openapi_spec=spec, client=api_client)if __name__ == "__main__": mcp.run()
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, FlashMCP 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:
# Simplified version of the actual mapping rulesDEFAULT_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, ),]
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.
from FlashMCP.server.openapi import RouteMap, RouteType# Custom mapping rulescustom_maps = [ # Force all analytics endpoints to be Tools RouteMap(methods=["GET"], pattern=r"^/analytics/.*", route_type=RouteType.TOOL)]# Apply custom mappingsmcp = await FlashMCP.from_openapi( openapi_spec=spec, client=api_client, route_maps=custom_maps)
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:
# Make all endpoints tools, regardless of HTTP methodmcp = FlashMCP.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:
# Same effect as all_routes_as_tools=Truemcp = FlashMCP.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.
By default, FlashMCP 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:
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.
For path parameters, which are typically required by REST APIs, FlashMCP 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.
# This will workawait 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})
import asyncioimport httpxfrom FlashMCP import FlashMCP# Sample OpenAPI spec for a Pet Store APIpetstore_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: FlashMCP): # 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 mcpif __name__ == "__main__": # Client for the Pet Store API client = httpx.AsyncClient(base_url="https://petstore.example.com/api") # Create the MCP server mcp = FlashMCP.from_openapi( openapi_spec=petstore_spec, client=client, name="PetStore" ) asyncio.run(check_mcp(mcp)) # Start the MCP server mcp.run()