Published on

Comprehensive Tutorial: Transforming FastAPI APIs into Intelligent Tools with FastAPI-MCP

44 min read
Authors
  • Profile picture of aithemes.net
    Name
    aithemes.net
    Twitter

FastAPI-MCP is a framework that extends FastAPI to seamlessly expose your API endpoints as Model Context Protocol (MCP) tools. This tutorial will guide you through everything from the basics to advanced usage of FastAPI-MCP, suitable for complete beginners and experienced FastAPI developers alike. We’ll cover conceptual explanations, component breakdowns, example code, and project-based illustrations. By the end, you’ll know how to set up FastAPI-MCP, configure it, secure it with dependencies (auth), integrate it with AI clients, deploy it, and test it in real-world scenarios.

Post image

Introduction to FastAPI-MCP

FastAPI is a popular Python web framework for building APIs quickly with automatic OpenAPI documentation. MCP (Model Context Protocol), on the other hand, is an emerging open standard that defines how AI assistants (like GPT-4, Anthropic’s Claude, etc.) communicate with applications and tools. Think of MCP as a “USB-C port for AI applications” – a universal interface that lets AI models discover and use external tools or data sources in a standardized way. Using MCP, AI models can:

  • Discover what tools (API operations) are available and what they do.
  • Understand how to invoke these tools (their inputs/outputs).
  • Retrieve data or execute operations via these tools in a unified manner.

FastAPI-MCP bridges the gap between your FastAPI APIs and the AI tooling ecosystem. In simple terms, FastAPI-MCP will automatically transform your existing FastAPI endpoints into MCP-compatible tools with minimal effort. This means you can expose your API to AI assistants (such as Claude in Cursor IDE, GPT in compatible clients, etc.) so that they can call your API operations securely and seamlessly.

Why Use FastAPI-MCP?

FastAPI-MCP offers a FastAPI-native, zero-configuration approach to AI integration. You don’t need to rewrite your API or deal with complex plugin specifications – FastAPI-MCP uses your existing FastAPI app and automatically builds an MCP interface on top of it. Key features include:

  • Native dependency integration – You can secure MCP tool calls using the same Depends() dependencies (e.g. for auth) that you use in FastAPI. This means existing authentication/authorization logic can be reused for AI-initiated calls.
  • Schema and docs preservation – It preserves the request/response models and documentation of your endpoints, just like your OpenAPI/Swagger docs. AI agents get the same info about parameters and responses as human developers would.
  • Zero/minimal configuration – Simply point FastAPI-MCP to your FastAPI app and it works out-of-the-box. No manual mapping or special decorators needed.
  • FastAPI-first design – It’s not just a converter from OpenAPI; it directly hooks into FastAPI’s routing and dependency system for efficiency and fidelity.
  • Built-in Authentication support – It supports adding auth requirements (API keys, OAuth2) for MCP endpoints using FastAPI dependencies or configurations.
  • Flexible deployment – You can mount the MCP server on the same app (same process) or serve it as a separate service; both modes are supported.
  • Efficient ASGI transport – By default, MCP calls are handled in-process via ASGI (no extra HTTP hop), making communication fast and not even requiring a base URL when co-hosted.

In summary, FastAPI-MCP makes it straightforward to turn your API into an AI-accessible interface. Next, we’ll dive into setting it up step by step.

Getting Started with FastAPI-MCP

Let’s start from scratch and build a simple FastAPI app, then enable MCP on it. This section will walk through installation, basic setup, and confirming that the MCP server is running.

Installation

FastAPI-MCP is a Python package. You can install it via pip or uv (a fast Python package manager recommended by the authors):

# Using uv (if you have it installed)
uv add fastapi-mcp

# Using pip
pip install fastapi-mcp

This will also install FastAPI (if not already) as a dependency. Ensure you have Python 3.10+ (FastAPI-MCP requires Python 3.10 or newer). You’ll likely also want to install Uvicorn to run the app, and any other FastAPI dependencies you plan to use (like pydantic, etc.). For example:

pip install fastapi uvicorn

Now you’re ready to create your FastAPI application and integrate MCP.

Basic Setup and Implementation

Step 1: Create a FastAPI app with an endpoint. If you already have a FastAPI app, you can use it; otherwise, let’s create a minimal one. In a file (e.g. main.py), write:

from fastapi import FastAPI

app = FastAPI()

# Define a sample endpoint (operation) as you normally would
@app.get("/items/{item_id}", operation_id="get_item")
async def read_item(item_id: int):
    """Retrieve an item by its ID"""
    return {"item_id": item_id, "name": f"Item {item_id}"}

This defines a simple GET endpoint /items/{item_id} that returns a JSON with the item ID and name. We’ve given it an explicit operation_id="get_item" – this is the name that will identify this endpoint as an MCP tool (more on this in the next section). If you don’t specify operation_id, FastAPI will auto-generate one, but it tends to be verbose (e.g. "read_item_items__item_id__get"), which is less intuitive.

Step 2: Mount FastAPI-MCP onto the app. With FastAPI-MCP, turning the above API into an MCP server is just a few lines of code. Continuing in main.py:

from fastapi_mcp import FastApiMCP

# ... (FastAPI app and endpoints as above) ...

# Create an MCP server instance for our app
mcp = FastApiMCP(
    app,
    name="My API MCP",                  # Optional name for the MCP service
    description="MCP server for my API" # Optional description
    # base_url="http://localhost:8000"  # Base URL, not required if using ASGI transport
)

# Mount the MCP server onto the FastAPI app
mcp.mount()

That’s it! By calling FastApiMCP(app) and mcp.mount(), we attach a fully functional MCP service to our FastAPI application. We provided a human-readable name and description for the MCP server (these metadata help clients identify it), and we could specify a base_url if needed. When mounted on the same app, FastAPI-MCP uses direct ASGI calls, so base_url is optional. (If you deploy the MCP separately from the main API, a base_url ensures the MCP knows where to send requests – we’ll discuss that scenario later.)

After mounting, FastAPI-MCP automatically registers a new route (by default at path /mcp) on your FastAPI app. This is the endpoint that MCP clients (AI agents or tools) will connect to.

Step 3: Run the application. Launch your app using Uvicorn (or your preferred ASGI server):

uvicorn main:app --reload --host 0.0.0.0 --port 8000

This starts the FastAPI app (with our /items/{item_id} route) and also the MCP server at the /mcp endpoint.

Step 4: Test the MCP endpoint. Open a browser (or use curl) and go to http://127.0.0.1:8000/mcp. You won’t see a typical JSON response; instead, because MCP uses Server-Sent Events (SSE) to communicate, your browser might keep the connection open and display an event stream. For example, you might see something like:

event: endpoint
data: /mcp/messages/?session_id=abcdef123456...

This is normal – it indicates the MCP server is running and ready. Essentially, the MCP endpoint immediately establishes a session for clients via SSE. (If you see raw SSE data as above, that’s expected since browsers don’t natively render SSE streams.)

You can also verify that your original API still works: try http://127.0.0.1:8000/items/42 – it should return {"item_id": 42, "name": "Item 42"} as usual. The FastAPI app’s normal functionality is unchanged; the MCP server is an add-on that runs alongside your API.

At this point, with minimal setup, you have an MCP-enabled FastAPI service. Your API’s capabilities (in this case, the single /items/{item_id} endpoint) are now discoverable and callable by any MCP-compatible AI agent. In the next sections, we’ll explore what exactly has been exposed, how to customize it, and how an AI client would use it.

Understanding MCP Tools and Services

Now that our MCP server is running, let’s clarify what FastAPI-MCP has created. Under the hood, FastAPI-MCP treats each API operation as a Tool in MCP terms, and the collection of tools served at the /mcp endpoint as a Service (MCP server service). Here’s a breakdown of the components:

  • MCP Server (Service): This is the service we mounted at /mcp. It acts as an interface for AI clients. When an AI agent connects to /mcp (usually via SSE), it can query what tools are available and invoke them. The MCP server takes care of listing your endpoints and routing calls to them.
  • MCP Tools: These are the individual operations (endpoints) from your FastAPI app that are exposed. Each FastAPI path operation becomes a tool with a name, description, input parameters schema, and output schema. By default, FastAPI-MCP names each tool after the endpoint’s operation_id. In our example, the /items/{item_id} endpoint has operation_id="get_item", so an AI client will see a tool called "get_item" – it knows this tool expects an item_id: int and returns an item object.

Tool Discovery and Documentation

One powerful aspect of FastAPI-MCP is that it auto-discovers all your FastAPI endpoints and exposes their metadata to AI. That includes: the path, the HTTP method, the expected input parameters (with types/constraints), and the response model or schema. Essentially, it mirrors what’s in your OpenAPI docs. For example, if you defined Pydantic models for request or response, those schemas are included in the tool description.

This means an AI agent can query the MCP server (usually by an initial "list tools" request) and get a list of tool names and descriptions. Each tool’s description includes what it does and how to use it. FastAPI-MCP uses the docstring and any description you provided in the FastAPI route as part of the tool’s description. So if you documented your endpoint (as we did with a docstring for read_item), the AI sees that. A well-documented API helps the AI choose and use tools correctly.

Operation IDs and Tool Naming: As mentioned, tool names derive from operation_id. If you don’t set one, FastAPI will auto-generate a name. These autogenerated names work, but are often long and not human-friendly. For AI agents, it’s beneficial to have descriptive, concise names – so it’s a best practice to set operation_id for each endpoint to something meaningful. For example, get_user_info for an endpoint that retrieves user info (rather than a default like read_user_users__user_id__get). Clear tool names make it easier for an AI to decide which tool to use for a given task.

If you already have an existing FastAPI app without operation_ids, you can add them without changing functionality (they only affect docs/specs). At minimum, ensure each endpoint’s operation_id is unique across the app.

How AI Agents Use MCP Tools

An AI agent (client) connected to your MCP server will typically:

  1. List available tools – The client requests the list of tools from the MCP server (this is often an automatic step when connecting). The MCP server responds with the names and descriptions of all included endpoints/tools. The agent now knows what it can do (e.g. it sees a tool get_item that retrieves an item by ID).
  2. Choose a tool and call it – When the AI’s reasoning decides to perform an action (say, “fetch item 42”), it will invoke the corresponding MCP tool. Under the hood, this means sending a request through the MCP protocol (which FastAPI-MCP translates into calling your FastAPI endpoint). The input parameters (like item_id=42) are passed, and FastAPI-MCP calls the read_item function just like a regular API call, then returns the result back to the AI client.
  3. Receive the result – The AI gets the endpoint’s response (here, {"item_id": 42, "name": "Item 42"}) through the MCP channel and can use it in its conversation or computation. The protocol ensures the response is structured (following the JSON schema of your endpoint).

All of this happens securely and in real-time. From the developer’s perspective, your FastAPI endpoint code doesn’t change at all – FastAPI-MCP handles converting the AI’s tool call into a normal function call to your endpoint and streaming the response back.

Important: MCP uses SSE streaming by default for responses, because some tool outputs might be large or streamed. FastAPI-MCP handles this for you. If a client connects via SSE, results are sent as events. If a client cannot handle SSE, they might use a proxy (discussed later). In either case, as the API developer you usually don’t need to worry about the streaming details – implement your endpoint normally (returning data or using StreamingResponse if you already stream). FastAPI-MCP will adapt it to MCP’s requirements.

Structuring a FastAPI-MCP Project

Whether you’re adding FastAPI-MCP to an existing project or starting a new one, you should organize your code in a maintainable way. In small demos, everything in one file is fine, but for larger projects consider the following structure:

myproject/
├── app.py          # FastAPI app and API route definitions
├── mcp_app.py      # (Optional) Separate FastAPI app for MCP if deploying separately
├── routes/         # Package for route modules, if you split your endpoints
│   ├── __init__.py
│   └── items.py    # e.g., defines /items endpoints
├── models/         # Data models (Pydantic models, etc.)
├── auth/           # Auth utilities (if any)
└── ... (other modules)

Single-app setup: If you plan to serve the MCP on the same application instance as your API (which is simplest), you can integrate it in your main application code. For example, in app.py after defining all your routes, you instantiate FastApiMCP(app) and call mcp.mount(). It’s often wise to create the MCP after all your routes are added, so that it captures every endpoint. This way, you don’t have to “refresh” the MCP when new routes are added (more on refreshing in a moment).

Separate-app setup (microservice style): In some cases, you might want to run the MCP server as a separate service from the main API. FastAPI-MCP supports that by allowing you to mount the MCP on a different FastAPI app. For example:

# file: api_app.py
from fastapi import FastAPI
api_app = FastAPI()
# ... define all your API endpoints on api_app ...

# file: mcp_app.py
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
from api_app import api_app  # import the other FastAPI app

mcp_app = FastAPI()                 # separate app just for MCP
mcp = FastApiMCP(api_app)           # create MCP from the API app
mcp.mount(mcp_app)                  # mount MCP routes onto the separate app

Here we have two FastAPI instances: api_app (with our regular endpoints) and mcp_app (which only serves the MCP interface). We pass api_app into FastApiMCP and mount it onto mcp_app. We would then run these two apps separately (e.g., uvicorn api_app:api_app on one host/port and uvicorn mcp_app:mcp_app on another). The MCP server will call into the other app internally. In this scenario, since they are separate processes, you should set the base_url in FastApiMCP to point to the API host (or provide a custom HTTP client) so that the MCP knows how to reach the API app. Alternatively, you can run them in the same process by mounting one app inside the other, but that’s less common.

Which setup to choose? For many cases, mounting MCP on the same app (perhaps under /mcp path) is perfectly fine and simpler. It keeps everything in one service to deploy. However, separate deployment might be useful if:

  • You want to scale or secure the MCP interface independently. For example, if the MCP service is for internal use by AI agents, you might host it on an internal network separate from the main API.
  • You want to run the MCP server on a different port or domain (maybe due to SSE or client requirements).
  • Your API is very performance sensitive and you prefer isolating the overhead of MCP (though MCP is lightweight).

FastAPI-MCP’s flexibility means you can start with it mounted together (for development convenience) and later split it out without changing your endpoint code – just adjust how you create and mount the MCP server.

Project structure tips: Keep your FastAPI app modular (use routers, separate files for logic), since FastAPI-MCP only needs the final FastAPI app object. If you add new routes after MCP is set up (for instance, dynamically or in an interactive setting), you’ll need to refresh the MCP server to pick them up (via mcp.setup_server() which re-scans endpoints). In a typical static app, just ensure all routes are defined before mounting MCP. If you ever forget and your new tools don’t appear, you can call mcp.setup_server() or recreate the MCP instance.

Configuration and Customization

FastAPI-MCP works with zero config by default, but it provides several options to customize the MCP server’s behavior and the exposed tools. Here we will discuss how to configure server metadata, enhance tool documentation, and filter which endpoints are exposed.

Server Metadata (Name & Description)

When creating FastApiMCP, you can pass a name and description for your MCP service. These help identify your service to clients. For example:

mcp = FastApiMCP(app, 
                 name="Inventory API MCP", 
                 description="MCP interface for my Inventory API")

In the MCP protocol, the server can present a name/description that clients might display in an interface. It’s optional but recommended to set, especially if you run multiple MCP services. By default, if not set, it may use a generic name. Setting a clear description (e.g. “Endpoints to manage inventory items”) can guide AI agents or developers about the purpose of the service.

Tool Descriptions and Response Schemas

FastAPI-MCP automatically uses your FastAPI documentation (path operation descriptions, Pydantic schema docs, etc.) to describe each tool. If you want to provide even richer descriptions for the AI, FastAPI-MCP offers flags to include more schema details:

  • describe_all_responses=True: include documentation of all possible response codes and schemas for the endpoint in the tool description. Normally, a tool description might focus on the main success response; with this, if you have multiple response models (e.g., error responses), those will be described too.
  • describe_full_response_schema=True: include the full JSON schema of the response model in the tool description. This can be very useful for AI agents to fully understand the structure of the output. For example, if your endpoint returns a nested JSON, the AI will know the exact fields and types expected.

You can enable these when instantiating FastApiMCP:

mcp = FastApiMCP(app,
                 describe_all_responses=True,
                 describe_full_response_schema=True)

Be mindful that extremely verbose descriptions might or might not help an AI model – it could be beneficial for precision, but some clients might truncate very long descriptions. Use these flags as needed, especially if your endpoints have complex outputs that the AI should be aware of.

Filtering Endpoints (Selective Exposure)

In many cases, you may not want every API endpoint exposed to AI agents. For instance, an application might have internal or admin endpoints that are not safe for an AI to use, or simply not relevant. FastAPI-MCP allows you to include or exclude endpoints by using their operation IDs or tags.

You have four main optional parameters for filtering tools:

  • include_operations: a list of operation IDs to include. Only these will become MCP tools (all others are ignored).
  • exclude_operations: a list of operation IDs to exclude (everything else will be included).
  • include_tags: only include endpoints that have any of these FastAPI tags. If you organize your routes by tags (e.g. tags=["public"]), you could expose only the “public” ones.
  • exclude_tags: exclude endpoints that have any of these tags.

Note: You cannot mix include and exclude of the same type – for example, you can’t use both include_operations and exclude_operations together. You can, however, combine operation filters with tag filters. The logic when combining is greedy union: endpoints matching any inclusion criteria are included, then any matching exclusion criteria are removed.

Examples:

  • Expose only specific endpoints:

    mcp = FastApiMCP(app, include_operations=["get_item", "list_items"])
    

    This would expose only the tools named get_item and list_items (and no other endpoints).

  • Exclude a dangerous endpoint:

    mcp = FastApiMCP(app, exclude_operations=["delete_item"])
    

    This exposes all endpoints except the one with operation_id “delete_item”. Useful if you want to block certain operations (like deletion or sensitive actions) from AI use.

  • By tags: Suppose you tag certain routes as admin or internal. Then:

    mcp = FastApiMCP(app, exclude_tags=["admin", "internal"])
    

    would expose everything except endpoints marked with those tags (ensuring internal APIs aren’t available to AI).

  • Combined: If you want to include only certain tags but also exclude one specific operation within those, you could do:

    mcp = FastApiMCP(app, include_tags=["public"], exclude_operations=["reset_database"])
    

    This would take all endpoints tagged "public" and expose them, except any one whose operation_id is "reset_database" even if it had that tag.

Using filtering, you can fine-tune the surface area of your API that is AI-accessible. A common strategy is to expose only read-only or safe operations and exclude anything that modifies data or performs critical actions (especially if your MCP server might be accessed by untrusted AI agents). This leads into security considerations which we’ll cover next.

Refreshing Tools on Changes

If your application is long-running and you dynamically add routes (perhaps via mounting new routers at runtime or other plugin systems), remember that FastAPI-MCP’s list of tools is built when you call mcp.mount() (or setup_server()). New endpoints added later won’t automatically appear until you refresh. You have two ways to handle this:

  1. Define all routes first, then create the MCP server. In normal startup, just order your code such that you finish adding routes to app before calling FastApiMCP(app) and mount(). This is the simplest approach and avoids any issues.

  2. Manually refresh if needed. If you must add a route after mounting MCP, call mcp.setup_server() afterwards to re-scan and register the new endpoint. Alternatively, you could re-initialize FastApiMCP (but setup_server() is easier). The FAQ notes this requirement: endpoints added post-creation are not seen until re-registering tools.

In development, it’s easy to forget – if you don’t see a tool you expect, double-check if the MCP was created too early. The log or SSE output might also warn that no tools were found if that happens.

Dependency Injection and Security (Authentication & Authorization)

Securing your API when accessed by AI is crucial. FastAPI-MCP allows you to leverage FastAPI’s dependency injection system to enforce authentication or other checks on MCP calls, just as you would on normal API calls. In other words, you can apply OAuth2, API key auth, permission checks, etc., to the MCP interface so that only authorized access is allowed.

Using FastAPI Dependencies for Auth

FastAPI endpoints often use dependencies (via Depends(), Security(), etc.) for authentication. For example, you might have:

from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/users/me")
async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token_and_get_user(token)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid or expired token")
    return {"username": user.username}

If you expose such an endpoint via MCP, an AI client would need to supply the Authorization header (with a Bearer token) to use it. FastAPI-MCP will honor all dependencies on the original endpoint. This means if the dependency raises an HTTPException (e.g. 401), the MCP call will also result in an error (and the AI will receive a failure).

However, not all AI clients can easily provide auth tokens out-of-the-box. Many current MCP clients are IDEs or agents that might not know about your auth. To handle this, FastAPI-MCP provides an auth_config or simpler dependencies argument that can enforce auth at the MCP layer and facilitate token passing.

Basic API Key or Token Authentication

The simplest way to secure the MCP server is to require an API key for all tool calls. You can do this by adding a dependency to FastApiMCP that checks a header. For example, using an API key header:

from fastapi import Security, HTTPException
from fastapi.security import APIKeyHeader

api_key_header = APIKeyHeader(name="X-API-Key")

async def verify_api_key(key: str = Security(api_key_header)):
    if key != "mysecret123":
        raise HTTPException(status_code=403, detail="Invalid API Key")
    return True

mcp = FastApiMCP(app, 
    # ensure every MCP request depends on verify_api_key
    auth_config=AuthConfig(dependencies=[Depends(verify_api_key)])
)
mcp.mount()

Now, any call to a tool through the MCP interface will require the header X-API-Key: mysecret123. If the header is missing or wrong, the MCP request will be rejected with 403 Forbidden. Essentially, this adds a global dependency on the MCP server itself.

Note: In older examples or simpler usage, you might see FastApiMCP(app, mcp_dependencies=[Depends(verify_api_key)]) which achieves the same effect. The latest approach wraps it in AuthConfig for more advanced options. Either way, the concept is the same: FastAPI-MCP can use a dependency to protect the tools.

For an API key scheme, the AI client needs to send that header. If you are using a tool like mcp-remote or a custom client, you can configure it to include headers on each request. For example, using mcp-remote (a Node-based proxy client), one can pass a header as:

"mcpServers": {
  "myapi": {
    "command": "npx",
    "args": ["mcp-remote", "http://localhost:8000/mcp", "--header", "X-API-Key:mysecret123"]
  }
}

This ensures the header is attached to every call, satisfying the dependency.

OAuth2 Authentication

FastAPI-MCP also supports the full OAuth2 authorization code flow as specified in the MCP spec (2025-03-26). This is more complex but allows a user-driven OAuth login if the client supports it. In practice, as of now many MCP clients do not fully support the interactive OAuth flows, so using an API token or API key (as above) might be more straightforward. If you do need OAuth2, you can configure AuthConfig with OAuth settings like issuer, authorization URL, token URL, etc. For example:

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"
))

This would advertise to the MCP client the OAuth details. The idea is that the AI agent (or user controlling it) could obtain a token via OAuth to use the tools. In practice, until AI client tooling catches up, you might rely on token passthrough or API keys.

Tip: You can combine approach: for instance, allow basic token passthrough and also have an auth dependency that checks for a valid token. The official documentation suggests that if you simply pass an Authorization: Bearer <token> header from the client, FastAPI-MCP will forward it to the FastAPI endpoints. So if your endpoints already expect a bearer token via Depends(oauth2_scheme), it will work as long as the client supplies it. Using mcp-remote --header Authorization:Bearer <token> is one way to ensure that.

Other Dependency Injection Uses

Aside from auth, your endpoints might use dependencies for other things (database session, etc.). The good news is all those still work normally. FastAPI-MCP calls your endpoint through the FastAPI app, so dependencies like db: Session = Depends(get_db) will run as usual. There is no difference between an AI-triggered call and a regular HTTP call in terms of how your endpoint code executes – the same dependency injection and context applies.

One thing to note: If a dependency expects certain context (like a request object or special headers), ensure the MCP client provides them or that your dependency can handle when they’re missing. For example, dependencies that rely on Request might behave differently under MCP since the “request” is the MCP call. But in most cases, it’s not an issue.

Security Best Practices: When exposing your API to AI via MCP, consider these guidelines (similar to normal API security, but with the unpredictability of AI agents in mind):

  • Expose only safe endpoints: Prefer read-only or idempotent operations. Be very cautious exposing anything that modifies data or performs irreversible actions. If you do, ensure authentication is required and maybe even an approval step outside MCP.
  • Require Auth for sensitive operations: Don’t rely on obscurity. If an endpoint returns sensitive data, protect it with proper auth even if you think “only the AI” knows about it. MCP listings could be accessible to any client with access. Use API keys or OAuth as appropriate.
  • Validate inputs strictly: Your endpoints should already do this (using Pydantic models, type hints). This is extra important when the caller is an AI that might make mistakes. Robust validation prevents the AI from accidentally passing invalid data or performing something unintended.
  • Sanitize outputs if needed: If certain data should be partially masked or processed before returning (for privacy or security), ensure your endpoint does that. Don’t assume the AI will handle confidentiality – it’s better the data leaving your server is safe.
  • Monitor usage: Keep logs of when tools are called and with what parameters. Monitoring how the AI uses your API can help identify misuse or needed improvements. You might detect patterns like an AI calling an endpoint too frequently or with odd parameters, which could indicate a misunderstanding that you can address by tweaking descriptions or adding constraints.

By using FastAPI’s robust dependency injection and security model, FastAPI-MCP allows you to enforce all these measures for AI access just as you would for human access.

Integrating with AI Clients and Tools

Once your FastAPI-MCP server is up and secured appropriately, the next step is to actually use it with an AI client. There are a few ways AI systems can connect to your MCP service:

  • Direct SSE Connection: Many AI IDEs or agent frameworks support MCP natively via SSE.
  • Proxy or Bridge (mcp-remote): A small proxy that handles SSE and advanced features, helpful if the client doesn’t support SSE or you need to inject auth.
  • Inspector or Testing tools: Useful for manual testing and debugging of your MCP interface.
  • Custom Integration (LangChain or custom code): You can write code to connect to an MCP server as well, though libraries for this are nascent.

Let’s explore the common methods.

Connecting via Server-Sent Events (Direct)

MCP servers (like FastAPI-MCP) fundamentally use Server-Sent Events for communication. Tools like Cursor IDE, Claude Desktop, Windsurf, VSCode extensions and others have begun supporting MCP by allowing you to configure an MCP endpoint.

For example, in Cursor (AI coding assistant IDE), you can add your MCP server in its settings. It might involve editing a config file mcp.json to include your server. According to one guide, you would add something like:

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

Here "fastapi-mcp" is just a label you give, and the url points to your running FastAPI-MCP endpoint. In Cursor, you’d go to Settings → MCP → Add new MCP server and input the URL. Once configured, the client will connect (often immediately or when you open an AI chat) to your MCP server.

What happens next? Typically, the IDE or client will now list new “tools” or capabilities. In Cursor’s case, you might see in the agent interface that your API’s tools (like get_item) are available for the AI to use. The AI model (with some system prompt engineering) is made aware of these tools. Now you can ask the AI to use them. For example, you could prompt: “Use the get_item tool to fetch item 42.” The AI, through the MCP integration, will call the tool and return the result in its answer.

To illustrate, after setting up, one could simply ask the AI (in Cursor’s agent tab): “Call the /items/42 endpoint for me.” The AI would detect that corresponds to the get_item tool and execute it, then likely respond with the data. This is incredibly powerful – the AI is effectively acting as a middleman to your API, allowing conversational or autonomous interactions with your service.

Most modern MCP-aware clients use SSE, so direct connection is often the simplest. Ensure your MCP server URL is accessible to the client (if you’re running both locally, localhost is fine; if the AI is remote, you’d need to expose a URL the AI can reach).

Using an MCP Proxy (for Auth or Incompatible Clients)

Not all AI clients support SSE or custom headers. For instance, Anthropic’s Claude Desktop (as of earlier versions) did not support SSE natively for MCP, and some tools might not allow you to add custom auth headers easily. In these cases, the recommended solution is to use mcp-remote (also referred to as mcp-proxy in some docs). This is an npm package that essentially acts as a bridge: it connects to your MCP server via SSE on one side, and offers a local stdio or WebSocket interface on the other side that the AI client can use.

For example, you might configure an MCP client entry like:

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

This would tell the system to run npx mcp-remote http://localhost:8000/mcp 8080. This command connects to your MCP endpoint and opens a local port 8080 that the AI can use. The AI would then actually connect to the proxy (which might present itself as an MCP server without SSE constraints). The proxy relays requests to your real FastAPI-MCP service and funnels responses back.

You can also pass headers through mcp-remote, as shown earlier, using --header "Authorization:Bearer XYZ" or similar, which is very handy for auth. Essentially, mcp-remote can inject those headers for you on each call, so the client doesn’t need to know about them.

Use mcp-remote if:

  • Your client doesn’t support providing the required auth headers or doesn’t support SSE.
  • You want to run the AI in an environment where a local port connection is easier than SSE (some cases for firewall or compatibility reasons).
  • You need to debug or log the traffic – running a proxy can let you see the requests going back and forth.

mcp-remote is a Node tool, so you need Node.js available in the environment where the AI client runs. The overhead is usually low.

MCP Inspector (Manual Testing)

Before involving an AI at all, you might want to manually test your MCP server to see what tools it exposes and ensure they work. The MCP Inspector is a command-line utility for this purpose, provided by the Model Context Protocol project. You can run it with npx as well:

npx @modelcontextprotocol/inspector

This will start an interactive prompt (likely in a browser) where you can input your MCP server URL and inspect it. Steps to use it:

  1. Make sure your FastAPI-MCP server is running.
  2. Run the inspector (npx @modelcontextprotocol/inspector).
  3. When prompted, enter the MCP endpoint URL (e.g. http://localhost:8000/mcp).
  4. The inspector will list the Tools available. You can select a tool and fill in parameters to test calling it, then click "Run Tool".
  5. You’ll see the response and can confirm everything is wired up correctly.

This is essentially like a Swagger UI but for MCP. It’s very helpful to confirm that your endpoints appear as expected and that authentication is working (if you set auth, you might need to provide headers in the inspector – it has options to add headers as well).

Integrating via Code (LangChain or Custom)

What if you want to build your own AI agent in Python that uses the MCP server? While you could directly use an HTTP client to connect to /mcp and handle SSE, that’s a bit low-level. There are libraries emerging to assist. For example, the fastapi-mcp GitHub repository mentions an MCP client and tools to compose servers. There’s also a project called FastMCP (jlowin/fastmcp) which can build MCP clients and even compose multiple MCP servers.

At this time, these are advanced topics, but an example approach could be:

  • Use Python’s httpx or requests to initiate a GET request to /mcp with stream=True to handle SSE events.
  • Parse the initial "endpoint" event to get the session or the control endpoint (often the protocol involves an initial message with a messages URL).
  • Send a command to list tools (MCP spec defines a message for that) and parse the response.
  • Invoke a specific tool by sending the appropriate JSON payload as an event or request.

This is beyond the scope of this tutorial, but be aware that, since MCP is an open standard (there’s an official spec and SDKs), you could integrate at that level if needed. For instance, a LangChain integration could treat the MCP server similar to how it treats OpenAI function calling or tools – one would need an adapter to translate a LangChain “tool” to an MCP tool call. We might see first-class libraries for MCP integration in Python soon, as the ecosystem grows.

For now, using existing AI clients or the inspector is the easiest way to work with your MCP server.

Deployment Strategies

Deploying a FastAPI-MCP application is very similar to deploying any FastAPI app. Because it’s just an ASGI application, you can use Uvicorn, Hypercorn, or Gunicorn (with Uvicorn workers) to run it, and containerize it with Docker if desired. However, keep in mind SSE and networking considerations:

  • Same-app deployment: If you mount MCP on the same FastAPI app, you’ll deploy one service. Make sure the environment can support SSE (most ASGI servers do – Uvicorn does out of the box). If behind a reverse proxy (like Nginx), configure it to not buffer SSE streams and to allow keep-alive connections.
  • Separate deployment: If you split API and MCP into separate services, you’ll deploy two apps. Ensure the MCP service knows how to reach the API service (via base_url or internal network). For instance, you might deploy your main API at api.example.com and the MCP at mcp.example.com, with the MCP’s http_client base URL set to https://api.example.com. They could also communicate over an internal address if colocated.

Example (Separate Deployment with Docker Compose): You might have two containers, one for the API and one for MCP. The MCP container could have an environment variable for the API URL. Using FastApiMCP(app, http_client=httpx.AsyncClient(base_url=os.getenv("API_URL"))) would direct calls to the API service. This way, the MCP container doesn’t need the API code imported – it could even call a completely different service as long as it has a compatible OpenAPI (though typically you’d just import the same FastAPI app as we showed earlier).

Scaling: If your API is heavy and you only expect moderate use of MCP (or vice versa), you can scale them independently. For example, run multiple replicas of the API behind a load balancer, and maybe only one or two MCP server instances are needed for the AI usage. Because MCP uses streaming, you might not put a load balancer in front of the MCP (to avoid breaking SSE), or use a sticky connection strategy.

HTTPS and Networking: If the AI client will connect from an external service (say, an online IDE or an agent running in the cloud), you’ll need to serve your MCP endpoint over HTTPS (for security, and because many clients may require it). This typically means putting it behind an SSL-terminating proxy or using a cloud service. There’s nothing MCP-specific about this – treat it as exposing an API endpoint. Use proper TLS, domain names, etc. If your MCP is for internal use only, you might not expose it publicly at all.

Refreshing and Updates: If you update your API with new endpoints, remember to redeploy or refresh the MCP service so that it knows about the new endpoints. If the MCP service is long-lived, a rolling restart or calling setup_server() (perhaps triggered by a deployment script) could be used to pick up changes.

In summary, deploy FastAPI-MCP as you would a FastAPI microservice. The main difference is ensuring SSE works end-to-end and planning whether it’s part of your main app or a standalone service. The official docs have a simple example showing separate uvicorn processes on different ports, but you can adapt that to any infrastructure.

Testing and Troubleshooting

Testing a FastAPI-MCP setup involves both verifying the traditional API behavior and the new MCP interface. Here are some strategies:

Testing the API Endpoints

First, continue to write tests for your FastAPI endpoints as usual (using TestClient from FastAPI or HTTP calls). FastAPI-MCP doesn’t change the logic of your endpoints, so unit tests and integration tests for them remain valid. Ensuring each endpoint returns expected data given inputs will indirectly ensure the MCP output is correct too.

Testing the MCP Interface

To specifically test the MCP layer, you can simulate an MCP client. As mentioned, the MCP Inspector tool is great for manual testing – it’s like an interactive test client. Use it during development to make sure all your tools are listed and working:

  • Run your app, connect the inspector, list tools. If something should be there and isn’t, check operation IDs and whether you called mount() after defining those routes.
  • Use the inspector to call each tool with valid and invalid inputs. For instance, test a required parameter missing and see that it returns a validation error (just as your API would via FastAPI’s validation). The inspector will show the error response.

For automated testing, you might write a small test that uses Python’s SSE client or websockets to connect to /mcp. Python doesn’t have built-in SSE support, but you could use httpx with an event-stream parser. However, this can get complicated. Another approach is to run a command like npx @modelcontextprotocol/inspector or mcp-remote in a test environment to ensure connection works (though that moves out of pure Python testing).

If your endpoints are simple, a pragmatic check is to see that GET http://localhost:8000/mcp returns a 200 and yields an event stream (you might parse the first event). For example:

from fastapi.testclient import TestClient

client = TestClient(app)
response = client.get("/mcp", stream=True)
assert response.status_code == 200
chunks = []
for chunk in response.iter_content(chunk_size=None):
    chunks.append(chunk.decode())
    if b"event: " in chunk:
        break
stream_output = "".join(chunks)
assert "event: endpoint" in stream_output or "event: tool_list" in stream_output

This is a bit hacky but it checks that the MCP endpoint produces an event. A more thorough test would mock an MCP client and perform the tool listing command.

Troubleshooting Tips

  • “No MCP tools available”: If the AI client says it found no tools, likely the MCP server didn’t register any endpoints. Ensure that FastApiMCP(app) was called after routes are set up (or call setup_server() to refresh). Also ensure you have not filtered out everything by accident with include/exclude settings.
  • Auth issues: If you protect the MCP with auth, and the AI client can’t connect, double-check that the client is sending the header or token. You might test using curl with the header to see if you get a 200 OK on /mcp. Example: curl -N http://localhost:8000/mcp -H "X-API-Key: mysecret123" (the -N is to not buffer output, so you see SSE). If this works, then the issue is the client configuration.
  • SSE connection closes immediately: This could happen if an error occurs on connect. Check your server logs; if your auth dependency raised an error due to missing token, the connection might drop. Or if an exception is thrown during tool listing. Logs will usually indicate the cause.
  • Tool call not working: If an AI says it tried to use a tool but got an error, treat it like an API call error. For example, the AI might provide a string where an int is expected, causing a 422 validation error. These errors are sent back through MCP as events – check logs or use the inspector to replicate the call. You may need to adjust your descriptions so the AI knows the correct types.
  • Performance: If calls are slow, remember that with SSE the connection stays open. Ensure you’re not doing something like reading request body in a way that stalls. Usually not a problem, but if using streaming responses, make sure to yield data properly. For heavy throughput, consider horizontal scaling.
  • MCP spec mismatches: As MCP is evolving, there could be slight version differences between clients and server. FastAPI-MCP aims to be up-to-date with the spec. If you encounter an incompatibility with a particular client, check the FastAPI-MCP release notes. A workaround can often be using mcp-remote since it tends to normalize communication.

By methodically testing both the API and the MCP interface, you can be confident in your deployment. It’s advisable to test with the actual AI client you expect to use (e.g., if your target is Cursor IDE users, test with Cursor; if it’s Claude Desktop, test via Claude with mcp-remote).

Real-World Examples and Use Cases

FastAPI-MCP opens up many possibilities for integrating APIs with AI. Here are a few scenarios to illustrate practical applications:

  • AI-Powered Documentation Assistant: Expose your public API endpoints via MCP so that an AI assistant can help users explore the API. For instance, a user could ask “How do I create a new user with this API?” and the AI (having access to the MCP tools) could find the create_user endpoint and even execute example calls. This provides an interactive documentation experience powered by AI.

  • Internal Developer Assistant: Within a company, developers could have an AI agent (in VSCode or Slack) connected to internal microservices via MCP. They could query data (read-only) or perform routine operations by instructing the AI in natural language. For example, “AI, get me the latest error logs from the monitoring service” – the AI calls the appropriate internal API and returns results. This can boost productivity by offloading simple queries to AI.

  • Multi-system Automation: Imagine an AI orchestrating tasks that involve multiple systems – e.g. an AI workflow that takes a support ticket, looks up user info from one service and product info from another, then creates an entry in a database. If each of those services has an MCP interface, the AI can seamlessly hop between them using standardized calls, without custom integration code for each system. MCP provides the glue for cross-system automation by AI.

  • Natural Language API for End Users: You could even expose certain tools to end-users via an AI chatbot. For example, a retail site could have a chatbot where the user asks “Where is my order with ID 12345?” The backend AI agent uses MCP to call the order tracking API (get_order_status) and then replies to the user with the info. FastAPI-MCP in this case is enabling the AI to use the same API that the mobile app or website might use, but through natural language interaction.

  • Prototype AI Plugin: If you were considering building an OpenAI Plugin for your API, implementing FastAPI-MCP achieves a similar goal but with an open standard that can work with multiple AI providers. For instance, Anthropic, OpenAI, and others are aligning on MCP. You get the benefit of a single implementation that works across many AI clients.

These are just a few ideas. The main takeaway is that FastAPI-MCP allows your API to be readily plugged into AI workflows with minimal effort. You focus on writing the API logic; FastAPI-MCP makes it AI-consumable.

Best Practices Recap

To ensure success when using FastAPI-MCP, keep in mind the following best practices (some we’ve touched on earlier):

  • Give tools clear names: Always set operation_id with a descriptive name for each endpoint. This helps AI (and humans) understand what the tool does (e.g. update_user_password vs. a vague default name). Use lower_case or lowerCamelCase by convention, and match names to actions.

  • Document your endpoints well: The more detail in your FastAPI docs (descriptions, examples, response model docstrings), the more context the AI has. Include example values for parameters if possible. FastAPI-MCP will carry over these descriptions to the MCP tool info.

  • Validate and sanitize thoroughly: Expect the AI to sometimes call your tools with incorrect parameters or in unintended ways. Make sure your FastAPI validators (Pydantic models, type checks) are in place to catch these and return proper errors. Also ensure responses don’t accidentally leak data – e.g. if your model includes a field that should be hidden, use response_model_exclude or similar.

  • Start restrictive, then open up carefully: Especially at the beginning, it might be wise to expose a limited set of endpoints to AI until you see how it uses them. You can include just a few safe read-only operations and test the waters. Over time, if needed, you can expose more. This limits risk.

  • Monitor AI usage: Enable logging for MCP calls. You could add middleware or simply watch the server logs (which will show requests to /mcp and possibly underlying endpoints). By monitoring, you can identify if the AI is struggling (e.g., calling one endpoint repeatedly without success) and then improve either your instructions or the endpoint’s design. It also helps detect misuse.

  • Stay updated with MCP spec changes: MCP is evolving (the spec link provided shows a date version). FastAPI-MCP likely will update to conform to new versions. Keep an eye on the FastAPI-MCP GitHub for releases, and update your package periodically to get improvements and bug fixes.

By following these practices, you ensure that integrating AI doesn’t compromise your API’s integrity or security, and that the AI can make the most of your API’s functionality.

Conclusion

FastAPI-MCP provides a powerful yet easy way to turn any FastAPI application into an AI-ready service. In this tutorial, we started from basic concepts and built up to advanced topics. Let’s quickly recap the journey:

  1. We learned what MCP is – a standard protocol for AI-tool communication, likened to giving AI a universal connector to use external APIs. FastAPI-MCP implements this for FastAPI, requiring just a few lines of code to set up.
  2. We walked through a quickstart – installing the package, mounting it on a FastAPI app, and verifying the MCP endpoint is live. With minimal code, our API endpoints became discoverable MCP tools.
  3. We discussed project structure – how to integrate in a single app or split into API and MCP services for flexibility. Planning your deployment early helps avoid refactoring later.
  4. We explored customization – naming tools via operation_id, adding detailed schema info, and filtering which endpoints are exposed to maintain control.
  5. We addressed security via dependency injection – using Depends() to require auth tokens or API keys for MCP calls, and even enabling OAuth flows for advanced scenarios. We emphasized using FastAPI’s existing security utilities to keep the MCP interface safe.
  6. We integrated with AI clients – demonstrating how an AI IDE can connect via SSE or through an mcp-remote proxy. We saw that an AI can then call API functions in natural language, effectively making your app a part of AI’s toolbox.
  7. We covered deployment – highlighting that you deploy FastAPI-MCP apps much like any FastAPI app, with attention to SSE and possibly separate scaling. Containerization and cloud deployment work seamlessly, enabling real-world use of your MCP service.
  8. We went over testing and troubleshooting – using tools like MCP Inspector to validate your setup, and noting common pitfalls (like forgetting to update the tool list or auth mismatches).
  9. We looked at real-world use cases – from documentation assistants to multi-system automation, illustrating the versatility of exposing an API to AI.
  10. Finally, we summarized best practices to ensure a smooth and secure operation when humans and AI start consuming your API in tandem.

By following this guide, you should be well-equipped to implement FastAPI-MCP in your projects. You can create rich, AI-integrated applications that leverage the power of large language models to interact with your FastAPI services in intelligent ways. As the MCP ecosystem grows (with more clients and servers emerging), you’re already on the cutting edge with an API that speaks the language of AI.

Next Steps: Experiment with your own API + MCP setup. Try connecting different AI clients to it (Cursor, VSCode, etc.) and see how the AI uses your tools. Join the FastAPI-MCP community (the “MCParty” Slack) if you have questions or ideas – being an open-source project, contributions and feedback are welcome. Happy coding, and welcome to the next generation of AI-powered applications!

References

Tip: The fastapi-mcp repo and the MCP spec are rapidly evolving—check those sources often to stay current.


Enjoyed this post? Found it insightful? Feel free to leave a comment below to share your thoughts or ask questions. A GitHub account is required to join the discussion.