MCPMCP Python SDK 2.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
24 small wins to finish your pathNext lesson

MCP inside a FastAPI app

A shop already running a FastAPI service does not need a second process. The MCP server can be mounted in the same app, next to its endpoints.

Exampleapp.py
from contextlib import asynccontextmanager

from fastapi import FastAPI

from shop import mcp

mcp_app = mcp.streamable_http_app()


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with mcp.session_manager.run():
        yield


app = FastAPI(lifespan=lifespan)


@app.get("/health")
def health():
    return {"status": "ok"}


app.mount("/", mcp_app)

mcp.streamable_http_app() returns the MCP server as a web application, and app.mount("/", mcp_app) puts it inside FastAPI, so /mcp is the MCP endpoint and /health is still yours. The mount goes last, because a mount at / matches every path and FastAPI checks routes in order.

The lifespan line is the one people forget. The MCP app starts its session manager in its own lifespan, and a mounted app's lifespan never runs. The host app has to start it, with async with mcp.session_manager.run(). Without it, the SDK docs show the first MCP request failing with Task group is not initialized.

Example
uvicorn app:app --port 8202 --log-level warning &
sleep 3
curl -s localhost:8202/health
echo
python client.py
kill %1

One process, one port: a normal FastAPI endpoint and an MCP server. The session manager's start-up line is the SDK's own log message.

Localhost only by default
The app accepts requests addressed to localhost only, as protection against DNS rebinding attacks. Deployed behind a real hostname, the SDK docs say every request is refused with 421 until that hostname is allowed through the transport_security setting.
Try it yourself
  • Remove the lifespan=lifespan argument, restart, and run the client.
  • Move app.mount above @app.get("/health") and call /health.
  • Add a FastAPI endpoint that calls lookup_order through Client(mcp).

You understood something today that you didn't yesterday.