|

FastAPI‑MCP: Turn Your FastAPI Endpoints into Secure MCP Tools in Minutes (Auth Included)

What if your existing FastAPI app could become an AI‑ready toolset—securely—without rewriting a single endpoint or wrestling with a converter? That’s exactly what FastAPI‑MCP delivers. It exposes your FastAPI routes as Model Context Protocol (MCP) tools, preserves your schemas and docs, and plugs into your existing authentication—all with near‑zero configuration.

If you’ve been curious about MCP and how it powers AI agents like Claude to call tools, this is your on‑ramp. In this guide, you’ll see how to turn your FastAPI services into robust, schema‑aware MCP tools that agents can reliably use in production. We’ll cover the why, the how, and the gotchas, plus give you code you can drop in today.

Let’s go from “What is MCP?” to “Deployed and secured” in one read.


What is the Model Context Protocol (MCP), and Why Should You Care?

Put simply, MCP is an open protocol that lets AI agents discover, describe, and safely call your tools. It standardizes how capabilities are exposed—using JSON schema, structured requests, and well‑defined responses—so agents can interact with your system in predictable, machine‑friendly ways.

Here’s why that matters: – Agents don’t guess—they follow schemas. – You maintain control—auth and permissions remain first‑class. – You reuse your existing API—no duplicate logic or brittle adapters.

Learn more about MCP here: – Model Context Protocol overview: modelcontextprotocol.io – MCP spec on GitHub: github.com/modelcontextprotocol/spec – Claude’s MCP docs: docs.anthropic.com/claude/docs/mcp-overview

Now, if you already have a FastAPI app, you’re 90% of the way there. The final step is exposing your routes as MCP tools—securely and with accurate schemas—without building a separate system. That’s what FastAPI‑MCP does best.


FastAPI‑MCP at a Glance: A FastAPI‑First Approach

FastAPI‑MCP is not a mere OpenAPI‑to‑MCP converter. It’s a FastAPI‑native extension that taps directly into your app’s ASGI interface. That gives you several practical advantages:

  • Uses your existing authentication and authorization via FastAPI Depends()
  • Preserves your request/response models and field descriptions
  • Mirrors your endpoint documentation (Swagger/OpenAPI) for agent discovery
  • Avoids extra network hops by calling in‑process via ASGI
  • Lets you mount the MCP server on the same app or deploy separately

In other words: you keep building with FastAPI patterns you know, and MCP gets a reliable, schema‑correct view of your endpoints.

Useful references: – FastAPI: fastapi.tiangolo.com – ASGI standard: asgi.readthedocs.io – Pydantic models: docs.pydantic.dev


Key Features You’ll Actually Use

Here are the headliners, with why they matter:

  • Authentication built in via FastAPI dependencies
  • Reuse your Depends() logic (JWT, API keys, OAuth2, RBAC), no parallel auth system.
  • FastAPI‑native (not just an OpenAPI converter)
  • Preserves the behavior and semantics of your app. No surprise mismatches.
  • Zero/minimal configuration
  • Point FastAPI‑MCP at your app. It “just works.”
  • Schema preservation
  • Your request and response models become MCP tool schemas. Agents parse them precisely.
  • Documentation preservation
  • Endpoint descriptions carry over—what you wrote for Swagger becomes guidance for agents.
  • Flexible deployment
  • Mount to the same FastAPI app or deploy separately for isolation.
  • ASGI transport
  • Communicates in‑process over the ASGI interface. No HTTP overhead between MCP and your API.
  • Hosted option
  • Prefer not to host yourself? Check out tadata.com.

Installation: uv or pip

We recommend uv, a blazing‑fast Python package installer.

  • With uv: uv add fastapi-mcp
  • With pip: pip install fastapi-mcp

Requirements: – Python 3.10+ (3.12 recommended) – FastAPI (of course) – An ASGI server like Uvicorn or Hypercorn


Quick Start: Turn Your FastAPI App into an MCP Server

Here’s the minimal setup. If you have a running FastAPI app, you can add MCP support in seconds.

from fastapi import FastAPI
from fastapi_mcp import FastApiMCP

app = FastAPI()

mcp = FastApiMCP(app)

# Mount the MCP server directly to your FastAPI app
mcp.mount()

That’s it. Your auto‑generated MCP server is now available at: – https://app.base.url/mcp

From there, a compliant MCP client (like an agent runtime) can discover your tools, read the schemas, and call your endpoints.


How Authentication Works with FastAPI‑MCP

This is where FastAPI‑MCP shines: it respects your existing dependencies and security patterns. Any auth you enforce with Depends() carries over to MCP calls because requests are routed through the ASGI layer to your actual endpoints.

Common patterns that “just work”: – OAuth2 Bearer tokens with JWT – API Key headers or query parameters – Signed cookies/sessions – Role‑based permissions checks – Per‑endpoint scopes

If you’ve implemented the standard FastAPI security utilities, you’re already compatible: – OAuth2 + JWT in FastAPI: fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ – JWT primer: jwt.io

Here’s a simple example using a dependency:

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

class User(BaseModel):
    username: str
    scopes: list[str] = []

def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
    # Verify and decode the token here (JWT verification, expiry, etc.)
    # For demo purposes only:
    if token != "valid-token":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    return User(username="alice", scopes=["read:widgets"])

@app.get("/widgets")
def list_widgets(user: User = Depends(get_current_user)):
    return [{"id": 1, "name": "Widget A"}]

Because MCP calls your app via ASGI, get_current_user runs as usual. No special wiring, no duplicated logic.

Pro tip: – If you use scopes (e.g., SecurityScopes in FastAPI), keep those checks inside dependencies so MCP routes inherit the same guardrails.


Schema and Documentation: What Agents See

Agents thrive on structured data and clear docs. FastAPI‑MCP preserves both:

  • Request/response model schemas (from Pydantic) are exposed as MCP tool parameters and results.
  • Field types and descriptions remain intact.
  • Endpoint docs (the descriptions that show in Swagger/Redoc) are carried over so agents can select the right tool and compose correct calls.

This accuracy improves: – Tool selection: Agents pick the right endpoint based on the doc summary. – Argument formation: Agents provide correctly shaped JSON aligned with your models. – Error recovery: Agents can use validation errors to retry with proper inputs.

If you’re using Pydantic models with docstrings or field descriptions, you’ve already done the hard work. FastAPI‑MCP simply carries it forward.

Learn more: – OpenAPI Initiative: openapis.org – FastAPI docs & path operations: fastapi.tiangolo.com/tutorial/path-params/


Why ASGI Transport Beats HTTP Bridging

Many “API to tool” adapters generate a new service that calls your API over HTTP. That introduces overhead, routing complexity, and error surface. FastAPI‑MCP uses ASGI to communicate with your app in‑process:

  • Lower latency: No loopback HTTP calls between services.
  • Fewer moving parts: No duplicate HTTP clients, retries, or service mesh rules.
  • Unified error handling: Exceptions flow through your existing FastAPI stack.
  • Consistent middleware: Your existing middleware (logging, tracing, CORS, rate limiting) applies.

If you’re familiar with ASGI, this design will feel natural: – ASGI: asgi.readthedocs.io – Starlette (the toolkit underneath FastAPI): www.starlette.io


Deployment Options: Mount or Separate

You have two straightforward paths:

1) Mount to the same FastAPI app – Easiest to start and maintain. – MCP is available at a subpath (e.g., /mcp). – Shares process resources and middleware with your app.

2) Deploy separately – Useful when you want process isolation, distinct scaling, or independent routing. – Still talks to your app via ASGI without HTTP hops. – A good fit for multi‑team orgs or multi‑tenant architectures.

Which should you choose? Start mounted for simplicity. If you need independent scaling, move the MCP server out to its own process later—your endpoint logic won’t change either way.


A More Complete Example: Models, Auth, and Rich Docs

Below is a small, production‑style example bringing it together.

from typing import Annotated, Optional
from fastapi import FastAPI, Depends, HTTPException, status, Query
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, Field
from fastapi_mcp import FastApiMCP

app = FastAPI(
    title="Widget Service",
    description="Manage widgets for your product catalog. All endpoints are MCP-enabled.",
    version="1.0.0",
)

# Security
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

class User(BaseModel):
    username: str
    scopes: list[str] = []

def require_token(token: str = Depends(oauth2_scheme)) -> User:
    # Validate token here: verify signature, issuer, audience, expiry, scopes, etc.
    if token != "valid-token":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    return User(username="alice", scopes=["read:widgets", "write:widgets"])

# Models
class WidgetIn(BaseModel):
    name: str = Field(..., description="Human-readable name of the widget")
    price: float = Field(..., ge=0, description="Retail price in USD")
    tags: list[str] = Field(default_factory=list, description="Optional tags for search and grouping")

class WidgetOut(WidgetIn):
    id: int = Field(..., description="Unique identifier for the widget")

db: dict[int, WidgetOut] = {}
_counter = 0

def create_widget_id() -> int:
    global _counter
    _counter += 1
    return _counter

@app.post("/widgets", response_model=WidgetOut, summary="Create a widget")
def create_widget(payload: WidgetIn, user: User = Depends(require_token)):
    widget = WidgetOut(id=create_widget_id(), **payload.model_dump())
    db[widget.id] = widget
    return widget

@app.get("/widgets/{widget_id}", response_model=WidgetOut, summary="Get a widget by ID")
def get_widget(widget_id: int, user: User = Depends(require_token)):
    if widget_id not in db:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Widget not found")
    return db[widget_id]

@app.get("/widgets", response_model=list[WidgetOut], summary="List widgets")
def list_widgets(
    q: Annotated[Optional[str], Query(description="Filter by name substring")] = None,
    user: User = Depends(require_token),
):
    items = list(db.values())
    if q:
        items = [w for w in items if q.lower() in w.name.lower()]
    return items

# Add MCP support
mcp = FastApiMCP(app)
mcp.mount()  # MCP available at /mcp

What this gives you: – Clearly documented schemas, preserved for agents – A consistent auth model through require_token – Developer‑friendly summaries that tools can use for routing decisions

Tip: write concise endpoint summaries and field descriptions. Agents use them too.


Observability and Debugging: See What Agents See

Because FastAPI‑MCP routes through your app stack, your existing observability continues to work:

  • Logging: Use FastAPI or Starlette middleware to log requests/responses.
  • Tracing: Instrument with OpenTelemetry and propagate context through MCP calls.
  • Metrics: Count tool invocations, model validation errors, and auth failures.

A simple logging middleware example:

from starlette.middleware.base import BaseHTTPMiddleware
import time
import logging

logger = logging.getLogger("mcp")

class RequestLoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start = time.time()
        response = await call_next(request)
        elapsed = (time.time() - start) * 1000
        logger.info("%s %s -> %s in %.2fms",
                    request.method, request.url.path, response.status_code, elapsed)
        return response

app.add_middleware(RequestLoggingMiddleware)

This will log your MCP calls too, since they’re standard ASGI requests hitting your routes.


Security Best Practices for MCP + FastAPI

Even though FastAPI‑MCP keeps you in familiar territory, a few best practices go a long way:

  • Centralize auth in dependencies
  • Enforce tokens, scopes, or API keys through Depends().
  • Validate inputs rigorously
  • Let Pydantic raise errors for invalid shapes and types.
  • Limit data exposure
  • Use response models to avoid returning internal/private fields.
  • Rate limit sensitive operations
  • Apply middleware or gateway‑level rate limiting to write operations.
  • Log and alert on auth failures
  • Correlate repeated failures to a client or token to detect misuse.
  • Use HTTPS everywhere
  • Terminate TLS at your load balancer or gateway to keep tokens secure in transit.

For reference: – FastAPI Security: fastapi.tiangolo.com/advanced/security/ – OAuth2 in FastAPI: fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ – OWASP API Security Top 10: owasp.org/API-Security/


Performance Tips: Keep It Snappy

FastAPI‑MCP already avoids an HTTP hop by using ASGI. You can push performance further by:

  • Running Uvicorn in workers
  • Example: uvicorn app:app --workers 4 --loop uvloop --http h11
  • Using Pydantic v2 (default in modern FastAPI) for faster validation
  • Caching hot reads
  • Memoize read‑heavy endpoints where appropriate
  • Avoiding large payloads in one go
  • Use pagination and filtering to keep response sizes agent‑friendly

When you do need HTTP for external services, use async clients and timeouts. Don’t block your event loop unnecessarily.


Hosted Option: Prefer Not to Run It Yourself?

If you’d rather use a managed solution for deployment, scaling, and reliability, check out tadata.com. It can be a good fit if: – Your team wants less ops overhead – You need enterprise features sooner – You’re aiming for quick time‑to‑market


Real‑World Use Cases

A few scenarios where FastAPI‑MCP shines:

  • Internal tools for ops
  • Expose “runbook” endpoints (rotate keys, flush cache, restart jobs) with strict auth.
  • Data access gateways
  • Serve read‑only data queries as typed tools for analysis agents.
  • Content pipelines
  • Let agents call endpoints to classify, transform, or enrich content with human‑readable reasons.
  • Customer support automations
  • Provide controlled access to ticket systems or account lookups with audit trails.

In each case, the combination of accurate schemas and your existing auth reduces risk and speeds adoption.


Development Workflow and Contributing

Thinking about extending FastAPI‑MCP or filing an issue? Great.

  • Start with Python 3.12 if possible—it’s faster and well‑supported.
  • Use uv for local installs and reproducible environments: github.com/astral-sh/uv
  • Explore the examples folder (provided by the project) for advanced patterns.
  • Open issues and pull requests—community input is welcome.

There’s also a community Slack: – Join the MCParty Slack to connect with MCP practitioners, share ideas, and ask questions.

Before contributing, read the project’s Contribution Guide to align on coding style and review practices.


Troubleshooting Common Snags

  • My MCP client can’t find any tools
  • Ensure mcp.mount() is called and your server is reachable at /mcp.
  • Verify you have at least one public FastAPI route defined.
  • Auth keeps failing
  • Check your token verification logic and how tokens are passed from the client.
  • Log incoming auth headers (redact sensitive values in logs).
  • Schema fields aren’t showing as expected
  • Confirm your Pydantic models have types and optional Field() descriptions.
  • Avoid returning raw dicts; return typed models for best schema fidelity.
  • Slow responses under load
  • Add workers, optimize database queries, and enable async I/O for external calls.

FAQ: People Also Ask

Q: What is MCP in the context of AI agents? A: MCP (Model Context Protocol) is an open standard that lets AI agents discover and call tools over a well‑defined interface. It uses schemas for inputs/outputs so agents can form correct requests and parse responses.

Q: How is FastAPI‑MCP different from an OpenAPI‑to‑MCP converter? A: Converters typically scrape your OpenAPI spec and generate a separate tool layer. FastAPI‑MCP is FastAPI‑native and uses ASGI to interact with your app directly. That preserves your auth, schemas, and docs more faithfully with less overhead.

Q: Do I have to re‑implement authentication for MCP? A: No. FastAPI‑MCP respects your Depends() security dependencies. If your endpoints require tokens or API keys, MCP calls must satisfy the same requirements.

Q: Can I use OAuth2/JWT with FastAPI‑MCP? A: Yes. Use FastAPI’s OAuth2 utilities and JWT verification in dependencies. MCP calls will go through the same checks. See FastAPI’s OAuth2/JWT guide.

Q: Does FastAPI‑MCP support separate deployment? A: Yes. You can mount the MCP server on the same app for simplicity or run it separately for isolation and independent scaling.

Q: Will my Pydantic models and endpoint docs appear in MCP? A: Yes. FastAPI‑MCP preserves request/response models and endpoint documentation, making tools easier for agents to understand and call.

Q: What are the performance implications? A: MCP calls are routed via ASGI, avoiding HTTP round‑trips between the MCP layer and your app. This reduces latency and complexity compared to HTTP‑bridged adapters.

Q: How do I install FastAPI‑MCP? A: Use uv (uv add fastapi-mcp) or pip (pip install fastapi-mcp). Make sure you’re on Python 3.10+ (3.12 recommended).

Q: Is there a hosted option? A: Yes. If you prefer a managed setup, consider tadata.com.

Q: Can I keep my Swagger/Redoc docs? A: Absolutely. FastAPI‑MCP preserves your docs—they’re now useful not just for humans, but for agents too.


The Bottom Line

FastAPI‑MCP makes it drop‑dead simple to expose your FastAPI endpoints as MCP tools—securely, accurately, and with almost no configuration. Because it’s FastAPI‑native and rides over ASGI, you keep your existing auth, models, and documentation, and you gain a clean interface for AI agents to use your app.

Next steps: – Install with uv: uv add fastapi-mcp – Add three lines to mount MCP to your app – Tighten your endpoint summaries and model descriptions – Test with your agent of choice

If you want deeper dives, examples, or hosted options, check the docs and explore tadata.com. And if this was helpful, keep learning—subscribe, bookmark, or share with a teammate who’s building agent integrations.

Discover more at InnoVirtuoso.com

I would love some feedback on my writing so if you have any, please don’t hesitate to leave a comment around here or in any platforms that is convenient for you.

For more on tech and other topics, explore InnoVirtuoso.com anytime. Subscribe to my newsletter and join our growing community—we’ll create something magical together. I promise, it’ll never be boring! 

Stay updated with the latest news—subscribe to our newsletter today!

Thank you all—wishing you an amazing day ahead!

Read more related Articles at InnoVirtuoso

Browse InnoVirtuoso for more!