LLM: MCP Server with FastAPI/FastMCP

07 February 2026, Carlos Pena

The Model Context Protocol (MCP) is an open standard that allows LLMs to interact with external tools and data sources. With FastMCP, you can turn any existing FastAPI application into an MCP server with minimal code changes, exposing your API endpoints as tools that LLM clients (like Claude Code) can discover and call directly.

This post walks through building a simple MCP server with FastAPI + FastMCP and connecting it to Claude Code.

Setup

uv add fastapi fastmcp uvicorn

MCP Server

FastMCP.from_fastapi() wraps an existing FastAPI app so that every endpoint is automatically registered as an MCP tool. The endpoint’s docstring becomes the tool description, and query/path parameters become tool parameters.

# uv run python -m main.py
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager

import uvicorn
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from fastmcp import FastMCP


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
    _ = app
    async with mcp_app.router.lifespan_context(mcp_app):
        yield


app = FastAPI(
    title="Dummy Project",
    version="v0.0.0",
    swagger_ui_parameters={"displayRequestDuration": True},
    lifespan=lifespan,
)


@app.get("/hidden_value")
async def select_hidden_value_endpoint(base_value: float) -> dict[str, int]:
    """
    Returns the hidden oracle value for testing purposes.
    Keep it simple and deterministic for local checks.

    output:
        {"result": int}
    """
    return {"result": int(base_value * 2)}


mcp = FastMCP.from_fastapi(app, name="Dummy Project")
mcp_app = mcp.http_app(transport="http", path="/")
app.mount("/mcp", mcp_app)


@app.get("/", response_class=RedirectResponse)
async def redirect_to_docs() -> str:
    """
    Redirect from ip:8000/ to ip:8000/docs
    """
    return "/docs"


@app.get("/health")
async def health_check() -> dict[str, str]:
    return {"status": "healthy"}


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Key points:

Claude Code Configuration

Register the MCP server in .claude/settings.json so Claude Code can discover and call your tools:

// .claude/settings.json
{
  "mcpServers": {
    "my-server-local": {
      "type": "http",
      "url": "http://localhost:8000/mcp/"
    }
  }
}

Verifying the MCP Connection

Once the server is running and Claude Code is configured, use the /mcp command inside Claude Code to verify the tools are registered:

❯ /mcp
───────────────────────────────────────────────────────────────────────────────────────────────────────────
 select_hidden_value_endpoint_hidden_value_get
 my-server-local

 Tool name: select_hidden_value_endpoint_hidden_value_get
 Full name: mcp__my-server-local__select_hidden_value_endpoint_hidden_value_get

 Description:
 Returns the hidden oracle value for testing purposes.
 Keep it simple and deterministic for local checks.

 output:
     {"result": int}

 Parameters:
   • base_value (required): number

 Esc to go back

The tool name, description, and parameters are all derived automatically from the FastAPI endpoint definition.