FastAPI-MCP: A Guide to Using MCP With FastAPI

August 22, 2025 (2mo ago)

Model Context Protocol (MCP) is an emerging standard that allows AI agents, IDE copilots, and LLM-based applications to call external tools in a structured way. Instead of sending arbitrary text prompts, an MCP client can discover available tools, inspect their schemas, and invoke them with validated inputs and outputs.

FastAPI-MCP is a library that bridges your FastAPI application with MCP. It automatically maps your existing routes into MCP tools, keeping your Pydantic validation, docs, and response models intact. This unlocks new ways for agents, copilots, and automation systems to interact with your API.


Why MCP Matters

Use cases:


Installation

uv add fastapi-mcp
# or
pip install fastapi-mcp

How Routes Become Tools

Each FastAPI endpoint becomes an MCP tool:

Example:

class TicketIn(BaseModel):
    title: str
    priority: int = 3
 
class TicketOut(BaseModel):
    id: str
    title: str
    priority: int
 
@app.post("/tickets", operation_id="ticket_create", response_model=TicketOut)
def create_ticket(payload: TicketIn) -> TicketOut:
    return TicketOut(id="t_123", **payload.dict())

MCP will expose a tool ticket_create that takes a validated payload and returns a TicketOut object.


Minimal Setup

from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
 
app = FastAPI()
 
mcp = FastApiMCP(app)
mcp.mount_http()

Run with Uvicorn. /mcp now exposes your tool list.


Connecting Clients

Direct HTTP:

{
  "mcpServers": { "fastapi-mcp": { "url": "http://localhost:8000/mcp" } }
}

SSE (legacy):

{
  "mcpServers": { "fastapi-mcp": { "url": "http://localhost:8000/sse" } }
}

Using mcp-remote: required for OAuth or older clients.

{
  "mcpServers": {
    "fastapi-mcp": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:8000/mcp", "8080"]
    }
  }
}

Authentication Options

Token Passthrough

Require a bearer token for access:

from fastapi import Depends
from fastapi_mcp import FastApiMCP, AuthConfig
 
def verify_auth():
    return True
 
mcp = FastApiMCP(app, auth_config=AuthConfig(dependencies=[Depends(verify_auth)]))
mcp.mount_http()

OAuth 2.0

Use when agents need full identity integration:

mcp = FastApiMCP(
    app,
    auth_config=AuthConfig(
        issuer="https://auth.example.com/",
        authorize_url="https://auth.example.com/authorize",
        oauth_metadata_url="https://auth.example.com/.well-known/oauth-authorization-server",
        audience="my-audience",
        client_id="my-client-id",
        client_secret="my-client-secret",
        setup_proxies=True,
    ),
)
mcp.mount_http()

Callback: http://127.0.0.1:8080/oauth/callback


Transport and Reliability

import httpx
client = httpx.AsyncClient(base_url="https://api.example.com", timeout=30.0)
mcp = FastApiMCP(app, http_client=client)

Deployment Patterns

api_app = FastAPI()
# endpoints
 
mcp_app = FastAPI()
mcp = FastApiMCP(api_app)
mcp.mount_http(mcp_app)

Development Workflow


Best Practices


Practical Example: CRM Tools

class Contact(BaseModel):
    id: str
    email: str
    name: str
 
DB = [
    Contact(id="1", email="ada@acme.com", name="Ada"),
    Contact(id="2", email="ben@acme.com", name="Ben"),
]
 
@app.get("/contacts", operation_id="crm_list_contacts")
def crm_list_contacts() -> list[Contact]:
    return DB
 
@app.get("/contacts/{contact_id}", operation_id="crm_get_contact")
def crm_get_contact(contact_id: str) -> Contact | None:
    return next((c for c in DB if c.id == contact_id), None)
 
mcp = FastApiMCP(app)
mcp.mount_http()

Agent clients can now query CRM data safely with validated inputs/outputs.


Debugging and Gotchas