From 9cbfcab94c4bb0c1ff8bd09c5271f6a0d315ce52 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:50:16 -0400 Subject: [PATCH] Update integration docs --- docs/deployment/asgi.mdx | 220 ---------------- docs/docs.json | 21 +- docs/integrations/fastapi.mdx | 229 +++++++++++++++++ docs/{servers => integrations}/openapi.mdx | 278 +++++++-------------- docs/integrations/starlette.mdx | 213 ++++++++++++++++ docs/servers/server.mdx | 28 ++- 6 files changed, 561 insertions(+), 428 deletions(-) delete mode 100644 docs/deployment/asgi.mdx create mode 100644 docs/integrations/fastapi.mdx rename docs/{servers => integrations}/openapi.mdx (74%) create mode 100644 docs/integrations/starlette.mdx diff --git a/docs/deployment/asgi.mdx b/docs/deployment/asgi.mdx deleted file mode 100644 index e5e6b6c71..000000000 --- a/docs/deployment/asgi.mdx +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: Integrating FastMCP in ASGI Applications -sidebarTitle: ASGI Integration -description: Integrate FastMCP servers into existing Starlette, FastAPI, or other ASGI applications -icon: plug ---- - -import { VersionBadge } from '/snippets/version-badge.mdx' - - -While FastMCP provides standalone server capabilities, you can also integrate your FastMCP server into existing web applications. This approach is useful for: - -- Adding MCP functionality to an existing website or API -- Mounting MCP servers under specific URL paths -- Combining multiple services in a single application -- Leveraging existing authentication and middleware - -Please note that all FastMCP servers have a `run()` method that can be used to start the server. This guide focuses on integration with broader ASGI frameworks. - -## ASGI Server - -FastMCP servers can be created as [Starlette](https://www.starlette.io/) ASGI apps for straightforward hosting or integration into existing applications. - -The first step is to obtain a Starlette application instance from your FastMCP server using the `http_app()` method: - - -The `http_app()` method is new in FastMCP 2.3.2. In older versions, use `sse_app()` for SSE transport or `streamable_http_app()` for Streamable HTTP transport. - - -```python -from fastmcp import FastMCP - -mcp = FastMCP("MyServer") - -@mcp.tool -def hello(name: str) -> str: - return f"Hello, {name}!" - -# Get a Starlette app instance for Streamable HTTP transport (recommended) -http_app = mcp.http_app() - -# For legacy SSE transport (deprecated) -sse_app = mcp.http_app(transport="sse") -``` - -Both approaches return a Starlette application that can be integrated with other ASGI-compatible web frameworks. - -The returned app stores the `FastMCP` instance on `app.state.fastmcp_server`, so you -can access it from custom middleware or routes via `request.app.state.fastmcp_server`. - -The MCP server's endpoint is mounted at the root path `/mcp/` for Streamable HTTP transport, and `/sse/` for SSE transport, though you can change these paths by passing a `path` argument to the `http_app()` method: - -```python -# For Streamable HTTP transport -http_app = mcp.http_app(path="/custom-mcp-path") - -# For SSE transport (deprecated) -sse_app = mcp.http_app(path="/custom-sse-path", transport="sse") -``` - -### Running the Server - -To run the FastMCP server, you can use the `uvicorn` ASGI server: - -```python -from fastmcp import FastMCP -import uvicorn - -mcp = FastMCP("MyServer") - -http_app = mcp.http_app() - -if __name__ == "__main__": - uvicorn.run(http_app, host="0.0.0.0", port=8000) -``` - -Or, from the command line: - -```bash -uvicorn path.to.your.app:http_app --host 0.0.0.0 --port 8000 -``` - -### Custom Middleware - - - -You can add custom Starlette middleware to your FastMCP ASGI apps by passing a list of middleware instances to the app creation methods: - -```python -from fastmcp import FastMCP -from starlette.middleware import Middleware -from starlette.middleware.cors import CORSMiddleware - -# Create your FastMCP server -mcp = FastMCP("MyServer") - -# Define custom middleware -custom_middleware = [ - Middleware( - CORSMiddleware, - allow_origins=["https://example.com", "https://app.example.com"], - allow_credentials=True, - allow_methods=["GET", "POST", "OPTIONS"], - allow_headers=["Content-Type", "Authorization"], - ), -] - -# Create ASGI app with custom middleware -http_app = mcp.http_app(middleware=custom_middleware) -``` - - -## Starlette Integration - - - -You can mount your FastMCP server in another Starlette application: - -```python -from fastmcp import FastMCP -from starlette.applications import Starlette -from starlette.routing import Mount - -# Create your FastMCP server as well as any tools, resources, etc. -mcp = FastMCP("MyServer") - -# Create the ASGI app -mcp_app = mcp.http_app(path='/mcp') - -# Create a Starlette app and mount the MCP server -app = Starlette( - routes=[ - Mount("/mcp-server", app=mcp_app), - # Add other routes as needed - ], - lifespan=mcp_app.lifespan, -) -``` - -The MCP endpoint will be available at `/mcp-server/mcp/` of the resulting Starlette app. - - -For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. - - -### Nested Mounts - - -You can create complex routing structures by nesting mounts: - -```python -from fastmcp import FastMCP -from starlette.applications import Starlette -from starlette.routing import Mount - -# Create your FastMCP server as well as any tools, resources, etc. -mcp = FastMCP("MyServer") - -# Create the ASGI app -mcp_app = mcp.http_app(path='/mcp') - -# Create nested application structure -inner_app = Starlette(routes=[Mount("/inner", app=mcp_app)]) -app = Starlette( - routes=[Mount("/outer", app=inner_app)], - lifespan=mcp_app.lifespan, -) -``` - -In this setup, the MCP server is accessible at the `/outer/inner/mcp/` path of the resulting Starlette app. - - -For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the *outer* Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. - -## FastAPI Integration - - - -FastAPI is built on Starlette, so you can mount your FastMCP server in a similar way: - -```python -from fastmcp import FastMCP -from fastapi import FastAPI -from starlette.routing import Mount - -# Create your FastMCP server as well as any tools, resources, etc. -mcp = FastMCP("MyServer") - -# Create the ASGI app -mcp_app = mcp.http_app(path='/mcp') - -# Create a FastAPI app and mount the MCP server -app = FastAPI(lifespan=mcp_app.lifespan) -app.mount("/mcp-server", mcp_app) -``` - -The MCP endpoint will be available at `/mcp-server/mcp/` of the resulting FastAPI app. - - -For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting FastAPI app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. - - - -## Custom Routes - -In addition to adding your FastMCP server to an existing ASGI app, you can also add custom web routes to your FastMCP server, which will be exposed alongside the MCP endpoint. To do so, use the `@custom_route` decorator. Note that this is less flexible than using a full ASGI framework, but can be useful for adding simple endpoints like health checks to your standalone server. - -```python -from fastmcp import FastMCP -from starlette.requests import Request -from starlette.responses import PlainTextResponse - -mcp = FastMCP("MyServer") - -@mcp.custom_route("/health", methods=["GET"]) -async def health_check(request: Request) -> PlainTextResponse: - return PlainTextResponse("OK") -``` - -These routes will be included in the FastMCP app when mounted in your web application. \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 041f95733..93f28284b 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -65,10 +65,7 @@ { "group": "Essentials", "icon": "cube", - "pages": [ - "servers/server", - "deployment/running-server" - ] + "pages": ["servers/server", "deployment/running-server"] }, { "group": "Core Components", @@ -97,11 +94,6 @@ "group": "Authentication", "icon": "shield-check", "pages": ["servers/auth/bearer"] - }, - { - "group": "Deployment", - "icon": "upload", - "pages": ["deployment/asgi"] } ] }, @@ -111,10 +103,7 @@ { "group": "Essentials", "icon": "cube", - "pages": [ - "clients/client", - "clients/transports" - ] + "pages": ["clients/client", "clients/transports"] }, { "group": "Core Operations", @@ -153,15 +142,17 @@ "integrations/claude-desktop", "integrations/cursor", "integrations/eunomia-authorization", + "integrations/fastapi", "integrations/gemini", "integrations/mcp-json-configuration", - "integrations/openai" + "integrations/openai", + "integrations/openapi", + "integrations/starlette" ] }, { "group": "Patterns", "pages": [ - "servers/openapi", "patterns/tool-transformation", "patterns/decorating-methods", "patterns/http-requests", diff --git a/docs/integrations/fastapi.mdx b/docs/integrations/fastapi.mdx new file mode 100644 index 000000000..2eece254f --- /dev/null +++ b/docs/integrations/fastapi.mdx @@ -0,0 +1,229 @@ +--- +title: FastAPI 🤝 FastMCP +sidebarTitle: FastAPI +description: Integrate FastMCP with FastAPI applications +icon: bolt +--- + +import { VersionBadge } from '/snippets/version-badge.mdx' + +FastMCP provides two powerful ways to integrate with FastAPI applications, both of which are documented below. + +1. You can [generate an MCP server FROM your FastAPI app](#generating-an-mcp-server) by converting existing API endpoints into MCP tools. This is useful for bootstrapping and quickly attaching LLMs to your API. +2. You can [mount an MCP server INTO your FastAPI app](#mounting-an-mcp-server) by adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints. + +You can even combine both approaches to create a single FastAPI app that serves both regular API endpoints and MCP tools! + + +Generating MCP servers from FastAPI apps is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted FastAPI servers. This is especially true for complex APIs with many endpoints and parameters. + + + +FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration. + + +## Generating an MCP Server + + + +FastMCP can directly convert your existing FastAPI applications into MCP servers, allowing AI models to interact with your API endpoints through the MCP protocol. + + + +Under the hood, the FastAPI integration is built on top of FastMCP's OpenAPI integration. See the [OpenAPI docs](/integrations/openapi) for more details. + + +### Create a Server + +The simplest way to convert a FastAPI app is using the `FastMCP.from_fastapi()` method: + +```python server.py +from fastapi import FastAPI +from fastmcp import FastMCP + +# Your existing FastAPI app +app = FastAPI(title="My API", version="1.0.0") + +@app.get("/items", tags=["items"], operation_id="list_items") +def list_items(): + return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}] + +@app.get("/items/{item_id}", tags=["items", "detail"], operation_id="get_item") +def get_item(item_id: int): + return {"id": item_id, "name": f"Item {item_id}"} + +@app.post("/items", tags=["items", "create"], operation_id="create_item") +def create_item(name: str): + return {"id": 3, "name": name} + +# Convert FastAPI app to MCP server +mcp = FastMCP.from_fastapi(app=app) + +if __name__ == "__main__": + mcp.run() # Run as MCP server +``` + +### Component Mapping + +By default, FastMCP converts **every endpoint** in your FastAPI app into an MCP **Tool**. This provides maximum compatibility with LLM clients that primarily support MCP tools. + +You can customize this behavior using route maps to control which endpoints become tools, resources, or resource templates: + +```python +from fastmcp.server.openapi import RouteMap, MCPType + +# Custom route mapping +mcp = FastMCP.from_fastapi( + app=app, + route_maps=[ + # GET requests with path parameters become ResourceTemplates + RouteMap(methods=["GET"], pattern=r".*\{.*\}.*", mcp_type=MCPType.RESOURCE_TEMPLATE), + # All other GET requests become Resources + RouteMap(methods=["GET"], pattern=r".*", mcp_type=MCPType.RESOURCE), + # POST/PUT/DELETE become Tools (handled by default rule) + ], +) +``` + +The `FastMCP.from_fastapi()` method accepts all the same configuration options as `FastMCP.from_openapi()`, including route maps, custom tags, component naming, timeouts, and component customization functions. For comprehensive configuration details, see the [OpenAPI Integration guide](/integrations/openapi). + +### Key Considerations + +#### Operation IDs + +FastMCP uses your FastAPI operation IDs to name MCP components. Ensure your endpoints have meaningful operation IDs: + +```python +@app.get("/users/{user_id}", operation_id="get_user_detail") # ✅ Good +@app.get("/users/{user_id}") # ❌ Auto-generated name might be unclear +``` + +#### Pydantic Models + +Your Pydantic models are automatically converted to JSON schema for MCP tool parameters: + +```python +from pydantic import BaseModel + +class CreateItemRequest(BaseModel): + name: str + description: str | None = None + price: float + +@app.post("/items") +def create_item(item: CreateItemRequest): + return {"id": 123, **item.dict()} +``` + +The MCP tool will have properly typed parameters matching your Pydantic model. + +#### Error Handling + +FastAPI error handling carries over to the MCP server. HTTPExceptions are automatically converted to appropriate MCP errors. + +Since FastAPI integration is built on OpenAPI, all the same configuration options are available including authentication setup, timeout configuration, and request parameter handling. For detailed information on these features, see the [OpenAPI Integration guide](/integrations/openapi). + +## Mounting an MCP Server + + + +You can also mount an existing FastMCP server into your FastAPI application, adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints. + +### Basic Integration + +```python +from fastmcp import FastMCP +from fastapi import FastAPI +from starlette.routing import Mount + +# Create your FastMCP server +mcp = FastMCP("MyServer") + +@mcp.tool +def analyze_data(query: str) -> dict: + """Analyze data based on the query.""" + return {"result": f"Analysis for: {query}"} + +# Create the ASGI app from your MCP server +mcp_app = mcp.http_app(path='/mcp') + +# Create a FastAPI app and mount the MCP server +app = FastAPI(lifespan=mcp_app.lifespan) +app.mount("/mcp-server", mcp_app) + +# Add regular FastAPI routes +@app.get("/health") +def health_check(): + return {"status": "healthy"} +``` + +The MCP endpoint will be available at `/mcp-server/mcp/` of your FastAPI application. + + +For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the FastAPI app. Otherwise, the FastMCP server's session manager will not be properly initialized. + + +### Advanced Integration + +You can combine both approaches - generate an MCP server from your FastAPI app AND mount additional MCP servers: + +```python +from fastmcp import FastMCP +from fastapi import FastAPI + +# Your existing FastAPI app +app = FastAPI() + +@app.get("/items") +def list_items(): + return [{"id": 1, "name": "Item 1"}] + +# Generate MCP server from FastAPI app +api_mcp = FastMCP.from_fastapi(app=app, name="API Server") + +# Create additional purpose-built MCP server +tools_mcp = FastMCP("Tools Server") + +@tools_mcp.tool +def advanced_analysis(data: dict) -> dict: + """Perform advanced analysis not available via API.""" + return {"analysis": "complex results"} + +# Mount the tools server into the same FastAPI app +tools_app = tools_mcp.http_app(path='/mcp') +app.mount("/tools", tools_app, lifespan=tools_app.lifespan) +``` + +Now you have: +- API endpoints converted to MCP tools (via `api_mcp`) +- Additional MCP tools available at `/tools/mcp/` +- Regular FastAPI endpoints at their original paths + +### Authentication and Middleware + +When mounting MCP servers into FastAPI, you can leverage FastAPI's authentication and middleware: + +```python +from fastapi import FastAPI, Depends, HTTPException +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials + +security = HTTPBearer() + +def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)): + if credentials.credentials != "secret-token": + raise HTTPException(status_code=401, detail="Invalid token") + return credentials + +app = FastAPI() + +# Mount MCP server with authentication +@app.get("/secure") +def secure_endpoint(auth=Depends(verify_token)): + return {"message": "Authenticated"} + +# The mounted MCP server inherits the app's security +mcp_app = mcp.http_app() +app.mount("/mcp", mcp_app, lifespan=mcp_app.lifespan) +``` + +For more advanced ASGI integration patterns, see the [ASGI Integration guide](/integrations/asgi). \ No newline at end of file diff --git a/docs/servers/openapi.mdx b/docs/integrations/openapi.mdx similarity index 74% rename from docs/servers/openapi.mdx rename to docs/integrations/openapi.mdx index 1359ff51b..805911e5c 100644 --- a/docs/servers/openapi.mdx +++ b/docs/integrations/openapi.mdx @@ -1,21 +1,25 @@ --- -title: OpenAPI Integration -sidebarTitle: OpenAPI Integration -description: Generate MCP servers from OpenAPI specs and FastAPI apps -icon: code-branch +title: OpenAPI 🤝 FastMCP +sidebarTitle: OpenAPI +description: Generate MCP servers from any OpenAPI specification +icon: list-tree --- + import { VersionBadge } from '/snippets/version-badge.mdx' -FastMCP can automatically generate an MCP server from an OpenAPI specification or FastAPI app. Instead of manually creating tools and resources, you provide an OpenAPI spec and FastMCP intelligently converts your API endpoints into the appropriate MCP components. +FastMCP can automatically generate an MCP server from any OpenAPI specification, allowing AI models to interact with existing APIs through the MCP protocol. Instead of manually creating tools and resources, you provide an OpenAPI spec and FastMCP intelligently converts API endpoints into the appropriate MCP components. -## Quick Start + +Generating MCP servers from OpenAPI is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted OpenAPI servers. This is especially true for complex APIs with many endpoints and parameters. + -To convert an OpenAPI specification to an MCP server, you can use the `FastMCP.from_openapi` class method. This method takes an OpenAPI specification and an async HTTPX client that can be used to make requests to the API, and returns an MCP server. +## Create a Server -Here's an example: -```python {11-15} +To convert an OpenAPI specification to an MCP server, use the `FastMCP.from_openapi()` class method: + +```python server.py import httpx from fastmcp import FastMCP @@ -36,8 +40,27 @@ if __name__ == "__main__": mcp.run() ``` -That's it! Your entire API is now available as an MCP server. Clients can discover and interact with your API endpoints through the MCP protocol, with full schema validation and type safety. +### Authentication +If your API requires authentication, configure it on the HTTP client: + +```python +import httpx +from fastmcp import FastMCP + +# Bearer token authentication +api_client = httpx.AsyncClient( + base_url="https://api.example.com", + headers={"Authorization": "Bearer YOUR_TOKEN"} +) + +# Create MCP server with authenticated client +mcp = FastMCP.from_openapi( + openapi_spec=spec, + client=api_client, + timeout=30.0 # 30 second timeout for all requests +) +``` ## Route Mapping @@ -51,7 +74,7 @@ Each `RouteMap` specifies a combination of methods, patterns, and tags, as well - **Pattern**: Regex pattern to match the route path (e.g. `r"^/users/.*"` or `r".*"` for all) - **Tags**: A set of OpenAPI tags that must all be present. An empty set (`{}`) means no tag filtering, so the route matches regardless of its tags. - **MCP type**: What MCP component type to create (`TOOL`, `RESOURCE`, `RESOURCE_TEMPLATE`, or `EXCLUDE`) -- **MCP tags** A set of custom tags to add to components created from matching routes +- **MCP tags**: A set of custom tags to add to components created from matching routes Here is FastMCP's default rule: @@ -70,7 +93,7 @@ When creating your FastMCP server, you can customize routing behavior by providi For example, prior to FastMCP 2.8.0, GET requests were automatically mapped to `Resource` and `ResourceTemplate` components based on whether they had path parameters. (This was changed solely for client compatibility reasons.) You can restore this behavior by providing custom route maps: -```python {2, 5-10} +```python from fastmcp import FastMCP from fastmcp.server.openapi import RouteMap, MCPType @@ -83,7 +106,8 @@ semantic_maps = [ ] mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_maps=semantic_maps, ) ``` @@ -97,9 +121,9 @@ from fastmcp import FastMCP from fastmcp.server.openapi import RouteMap, MCPType mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_maps=[ - # Analytics `GET` endpoints are tools RouteMap( methods=["GET"], @@ -132,12 +156,13 @@ To exclude routes from the MCP server, use a route map to assign them to `MCPTyp You can use this to remove sensitive or internal routes by targeting them specifically: -```python {7,8} +```python from fastmcp import FastMCP from fastmcp.server.openapi import RouteMap, MCPType mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_maps=[ RouteMap(pattern=r"^/admin/.*", mcp_type=MCPType.EXCLUDE), RouteMap(tags={"internal"}, mcp_type=MCPType.EXCLUDE), @@ -146,15 +171,17 @@ mcp = FastMCP.from_openapi( ``` Or you can use a catch-all rule to exclude everything that your maps don't handle explicitly: -```python {10} + +```python from fastmcp import FastMCP from fastmcp.server.openapi import RouteMap, MCPType mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_maps=[ # custom mapping logic goes here - ..., + # ... your specific route maps ... # exclude all remaining routes RouteMap(mcp_type=MCPType.EXCLUDE), ], @@ -165,7 +192,6 @@ mcp = FastMCP.from_openapi( Using a catch-all exclusion rule will prevent the default route mappings from being applied, since it will match every remaining route. This is useful if you want to explicitly allow-list certain routes. - ### Advanced Route Mapping @@ -178,7 +204,6 @@ In addition to more precise targeting of methods, patterns, and tags, this funct The `route_map_fn` **is** called on routes that matched `MCPType.EXCLUDE` in your custom maps, giving you an opportunity to override the exclusion. - ```python from fastmcp import FastMCP from fastmcp.server.openapi import RouteMap, MCPType, HTTPRoute @@ -200,12 +225,40 @@ def custom_route_mapper(route: HTTPRoute, mcp_type: MCPType) -> MCPType | None: return None mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_map_fn=custom_route_mapper, ) ``` -## Customizing MCP Components +## Customization + +### Component Names + + + +FastMCP automatically generates names for MCP components based on the OpenAPI specification. By default, it uses the `operationId` from your OpenAPI spec, up to the first double underscore (`__`). + +All component names are automatically: +- **Slugified**: Spaces and special characters are converted to underscores or removed +- **Truncated**: Limited to 56 characters maximum to ensure compatibility +- **Unique**: If multiple components have the same name, a number is automatically appended to make them unique + +For more control over component names, you can provide an `mcp_names` dictionary that maps `operationId` values to your desired names. The `operationId` must be exactly as it appears in the OpenAPI spec. The provided name will always be slugified and truncated. + +```python +mcp = FastMCP.from_openapi( + openapi_spec=spec, + client=client, + mcp_names={ + "list_users__with_pagination": "user_list", + "create_user__admin_required": "create_user", + "get_user_details__admin_required": "user_detail", + } +) +``` + +Any `operationId` not found in `mcp_names` will use the default strategy (operationId up to the first `__`). ### Tags @@ -217,12 +270,12 @@ FastMCP provides several ways to add tags to your MCP components, allowing you t You can add custom tags to components created from specific routes using the `mcp_tags` parameter in `RouteMap`. These tags will be applied to all components created from routes that match that particular route map. -```python {12, 20, 28} -from fastmcp import FastMCP +```python from fastmcp.server.openapi import RouteMap, MCPType mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, route_maps=[ # Add custom tags to all POST endpoints RouteMap( @@ -253,59 +306,18 @@ mcp = FastMCP.from_openapi( #### Global Tags -You can add tags to **all** components by providing a `tags` parameter when creating your FastMCP server with `from_openapi` or `from_fastapi`. These global tags will be applied to every component created from your OpenAPI specification. - - -```python {6} from_openapi() -from fastmcp import FastMCP +You can add tags to **all** components by providing a `tags` parameter when creating your MCP server. These global tags will be applied to every component created from your OpenAPI specification. +```python mcp = FastMCP.from_openapi( openapi_spec=spec, client=client, tags={"api-v2", "production", "external"} ) ``` -```python {5} from_fastapi() -from fastmcp import FastMCP - -mcp = FastMCP.from_fastapi( - app=app, - tags={"internal-api", "microservice"} -) -``` - - - -### Names - - - -FastMCP automatically generates names for MCP components based on the OpenAPI specification. By default, it uses the `operationId` from your OpenAPI spec, up to the first double underscore (`__`). - -All component names are automatically: -- **Slugified**: Spaces and special characters are converted to underscores or removed -- **Truncated**: Limited to 56 characters maximum to ensure compatibility -- **Unique**: If multiple components have the same name, a number is automatically appended to make them unique - -For more control over component names, you can provide an `mcp_names` dictionary that maps `operationId` values to your desired names. The `operationId` must be exactly as it appears in the OpenAPI spec. The provided name will always be slugified and truncated. - -```python {5-9} -from fastmcp import FastMCP - -mcp = FastMCP.from_openapi( - ... - mcp_names={ - "list_users__with_pagination": "user_list", - "create_user__admin_required": "create_user", - "get_user_details__admin_required": "user_detail", - } -) -``` - -Any `operationId` not found in `mcp_names` will use the default strategy (operationId up to the first `__`). - ### Advanced Customization + By default, FastMCP creates MCP components using a variety of metadata from the OpenAPI spec, such as incorporating the OpenAPI description into the MCP component description. @@ -316,8 +328,7 @@ At times you may want to modify those MCP components in a variety of ways, such Your `mcp_component_fn` is expected to modify the component in-place, not to return a new component. The result of the function is ignored. -```python {27} -from fastmcp import FastMCP +```python from fastmcp.server.openapi import ( HTTPRoute, OpenAPITool, @@ -329,7 +340,6 @@ def customize_components( route: HTTPRoute, component: OpenAPITool | OpenAPIResource | OpenAPIResourceTemplate, ) -> None: - # Add custom tags to all components component.tags.add("openapi") @@ -342,10 +352,12 @@ def customize_components( component.tags.add("data") mcp = FastMCP.from_openapi( - ..., + openapi_spec=spec, + client=client, mcp_component_fn=customize_components, ) ``` + ## Request Parameter Handling FastMCP intelligently handles different types of parameters in OpenAPI requests: @@ -401,118 +413,4 @@ FastMCP handles array parameters according to OpenAPI specifications: ### Headers -Header parameters are automatically converted to strings and included in the HTTP request. - -## Auth - -If your API requires authentication, configure it on the HTTP client before creating the MCP server: - -```python -import httpx -from fastmcp import FastMCP - -# Bearer token authentication -api_client = httpx.AsyncClient( - base_url="https://api.example.com", - headers={"Authorization": "Bearer YOUR_TOKEN"} -) - -# Create MCP server with authenticated client -mcp = FastMCP.from_openapi(..., client=api_client) -``` -## Timeouts - -Set a timeout for all API requests: - -```python -mcp = FastMCP.from_openapi( - openapi_spec=spec, - client=api_client, - timeout=30.0 # 30 second timeout for all requests -) -``` - - -## FastAPI Integration - - - -FastMCP can directly convert FastAPI applications into MCP servers by extracting their OpenAPI specifications: - - -FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration. - - -```python -from fastapi import FastAPI -from fastmcp import FastMCP - -# Your FastAPI app -app = FastAPI(title="My API", version="1.0.0") - -@app.get("/items", tags=["items"], operation_id="list_items") -def list_items(): - return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}] - -@app.get("/items/{item_id}", tags=["items", "detail"], operation_id="get_item") -def get_item(item_id: int): - return {"id": item_id, "name": f"Item {item_id}"} - -@app.post("/items", tags=["items", "create"], operation_id="create_item") -def create_item(name: str): - return {"id": 3, "name": name} - -# Convert FastAPI app to MCP server -mcp = FastMCP.from_fastapi(app=app) - -if __name__ == "__main__": - mcp.run() # Run as MCP server -``` - -Note that operation ids are optional, but are used to create component names. You can also provide custom names, just like with OpenAPI specs. - - -FastMCP servers are not FastAPI apps, even when created from one. To learn how to deploy them as an ASGI app, see the [ASGI Integration](/deployment/asgi) documentation. - - - - -### FastAPI Configuration - -All OpenAPI integration features work with FastAPI apps: - -```python -from fastmcp.server.openapi import RouteMap, MCPType - -# Custom route mapping with FastAPI -mcp = FastMCP.from_fastapi( - app=app, - name="My Custom Server", - timeout=5.0, - tags={"api-v1", "fastapi"}, # Global tags for all components - mcp_names={"operationId": "friendly_name"}, # Custom component names - route_maps=[ - # Admin endpoints become tools with custom tags - RouteMap( - methods="*", - pattern=r"^/admin/.*", - mcp_type=MCPType.TOOL, - mcp_tags={"admin", "privileged"} - ), - # Internal endpoints are excluded - RouteMap(methods="*", pattern=r".*", mcp_type=MCPType.EXCLUDE, tags={"internal"}), - ], - route_map_fn=my_route_mapper, - mcp_component_fn=my_component_customizer, - mcp_names={ - "get_user_details_users__user_id__get": "get_user_details", - } -) -``` - -### FastAPI Benefits - -- **Zero code duplication**: Reuse existing FastAPI endpoints -- **Schema inheritance**: Pydantic models and validation are preserved -- **ASGI transport**: Direct in-memory communication (no HTTP overhead) -- **Full FastAPI features**: Dependencies, middleware, authentication all work +Header parameters are automatically converted to strings and included in the HTTP request. \ No newline at end of file diff --git a/docs/integrations/starlette.mdx b/docs/integrations/starlette.mdx new file mode 100644 index 000000000..68378dea2 --- /dev/null +++ b/docs/integrations/starlette.mdx @@ -0,0 +1,213 @@ +--- +title: Starlette / ASGI 🤝 FastMCP +sidebarTitle: Starlette / ASGI +description: Integrate FastMCP servers into ASGI applications +icon: server +--- + +import { VersionBadge } from '/snippets/version-badge.mdx' + + + +FastMCP servers can be integrated into existing ASGI applications, allowing you to add MCP functionality to your web applications. This is useful for: + +- Adding MCP functionality to an existing website or API +- Mounting MCP servers under specific URL paths +- Combining multiple services in a single application +- Leveraging existing authentication and middleware + +## Basic Usage + +To integrate a FastMCP server into an ASGI application, use the `http_app()` method to obtain a Starlette application instance: + + +The `http_app()` method is new in FastMCP 2.3.2. In older versions, use `sse_app()` for SSE transport or `streamable_http_app()` for Streamable HTTP transport. + + +```python +from fastmcp import FastMCP + +mcp = FastMCP("MyServer") + +@mcp.tool +def hello(name: str) -> str: + return f"Hello, {name}!" + +# Get a Starlette app instance for Streamable HTTP transport (recommended) +http_app = mcp.http_app() + +# For legacy SSE transport (deprecated) +sse_app = mcp.http_app(transport="sse") +``` + +The returned Starlette application can be integrated with other ASGI-compatible web frameworks. The MCP server's endpoint is mounted at `/mcp/` for Streamable HTTP transport and `/sse/` for SSE transport. + +### Configuration Options + +You can customize the endpoint path and access the FastMCP server instance: + +```python +# Custom endpoint path +http_app = mcp.http_app(path="/custom-mcp-path") + +# Access the FastMCP server from middleware/routes +# The server is available at: request.app.state.fastmcp_server +``` + +### Adding Custom Routes + +You can add custom web routes directly to your FastMCP server using the `@custom_route` decorator: + +```python +from fastmcp import FastMCP +from starlette.requests import Request +from starlette.responses import JSONResponse + +mcp = FastMCP("MyServer") + +@mcp.custom_route("/api/status", methods=["GET"]) +async def get_status(request: Request): + return JSONResponse({"server": "running"}) + +http_app = mcp.http_app() +``` + +#### Health Check Endpoints + +Health checks are commonly needed for monitoring and load balancing: + +```python +from fastmcp import FastMCP +from starlette.requests import Request +from starlette.responses import JSONResponse + +mcp = FastMCP("MyServer") + +@mcp.custom_route("/health", methods=["GET"]) +async def health_check(request: Request): + return JSONResponse({"status": "healthy"}) + +http_app = mcp.http_app() +``` + +The health endpoint will be available at `/health` alongside your MCP endpoint at `/mcp/`. + +## Starlette Integration + +Mount your FastMCP server in another Starlette application: + +```python +from fastmcp import FastMCP +from starlette.applications import Starlette +from starlette.routing import Mount + +# Create your FastMCP server +mcp = FastMCP("MyServer") + +@mcp.tool +def analyze(data: str) -> dict: + return {"result": f"Analyzed: {data}"} + +# Create the ASGI app +mcp_app = mcp.http_app(path='/mcp') + +# Create a Starlette app and mount the MCP server +app = Starlette( + routes=[ + Mount("/mcp-server", app=mcp_app), + # Add other routes as needed + ], + lifespan=mcp_app.lifespan, +) +``` + +The MCP endpoint will be available at `/mcp-server/mcp/` of the resulting Starlette app. + + +For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized. + + +### Nested Mounts + +You can create complex routing structures by nesting mounts: + +```python +from fastmcp import FastMCP +from starlette.applications import Starlette +from starlette.routing import Mount + +# Create your FastMCP server +mcp = FastMCP("MyServer") + +# Create the ASGI app +mcp_app = mcp.http_app(path='/mcp') + +# Create nested application structure +inner_app = Starlette(routes=[Mount("/inner", app=mcp_app)]) +app = Starlette( + routes=[Mount("/outer", app=inner_app)], + lifespan=mcp_app.lifespan, +) +``` + +In this setup, the MCP server is accessible at the `/outer/inner/mcp/` path. + +## Custom Middleware + + + +Add custom Starlette middleware to your FastMCP ASGI apps by passing a list of middleware instances: + +```python +from fastmcp import FastMCP +from starlette.middleware import Middleware +from starlette.middleware.cors import CORSMiddleware + +# Create your FastMCP server +mcp = FastMCP("MyServer") + +# Define custom middleware +custom_middleware = [ + Middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], + ) +] + +# Create ASGI app with middleware +http_app = mcp.http_app(custom_middleware=custom_middleware) +``` + +## Running the Server + +To run your ASGI application, use an ASGI server like `uvicorn`: + +```python +import uvicorn + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +Or from the command line: + +```bash +uvicorn path.to.your.app:app --host 0.0.0.0 --port 8000 +``` + +## Framework-Specific Integration + +### FastAPI + +For FastAPI-specific integration patterns including both mounting MCP servers into FastAPI apps and generating MCP servers from FastAPI apps, see the [FastAPI Integration guide](/integrations/fastapi). + +### Other ASGI Frameworks + +The patterns shown here work with any ASGI-compatible framework. The key requirements are: + +1. Mount the FastMCP ASGI app at your desired path +2. Pass the lifespan context to your root application +3. Configure any necessary middleware or authentication + diff --git a/docs/servers/server.mdx b/docs/servers/server.mdx index 1680dbf8e..deb5d5f27 100644 --- a/docs/servers/server.mdx +++ b/docs/servers/server.mdx @@ -232,6 +232,28 @@ proxy = FastMCP.as_proxy(backend, name="ProxyServer") # Now use the proxy like any FastMCP server ``` +## OpenAPI Integration + + + +FastMCP can automatically generate servers from OpenAPI specifications or existing FastAPI applications using `FastMCP.from_openapi()` and `FastMCP.from_fastapi()`. This allows you to instantly convert existing APIs into MCP servers without manual tool creation. + +See the [FastAPI Integration](/integrations/fastapi) and [OpenAPI Integration](/integrations/openapi) guides for detailed examples and configuration options. + +```python +import httpx +from fastmcp import FastMCP + +# From OpenAPI spec +spec = httpx.get("https://api.example.com/openapi.json").json() +mcp = FastMCP.from_openapi(openapi_spec=spec, client=httpx.AsyncClient()) + +# From FastAPI app +from fastapi import FastAPI +app = FastAPI() +mcp = FastMCP.from_fastapi(app=app) +``` + ## Server Configuration Servers can be configured using a combination of initialization arguments, global settings, and transport-specific settings. @@ -322,12 +344,12 @@ await mcp.run_async( ) ``` -### Environment Variables +### Setting Global Configuration -Settings can be configured via environment variables: +Global FastMCP settings can be configured via environment variables (prefixed with `FASTMCP_`): ```bash -# Global settings +# Configure global FastMCP behavior export FASTMCP_LOG_LEVEL=DEBUG export FASTMCP_MASK_ERROR_DETAILS=True export FASTMCP_RESOURCE_PREFIX_FORMAT=protocol