|
| 1 | +""" |
| 2 | +Example showing ASGI route mounting with lifespan context management. |
| 3 | +
|
| 4 | +From the repository root: |
| 5 | + cd examples/snippets/servers |
| 6 | + uv run streamable_uvicorn_lifespan.py |
| 7 | +""" |
| 8 | + |
| 9 | +import contextlib |
| 10 | + |
| 11 | +from starlette.applications import Starlette |
| 12 | +from starlette.routing import Mount |
| 13 | + |
| 14 | +from mcp.server.fastmcp import FastMCP |
| 15 | + |
| 16 | +# Create MCP server |
| 17 | +mcp = FastMCP(name="My App", stateless_http=True) |
| 18 | + |
| 19 | + |
| 20 | +@mcp.tool() |
| 21 | +def ping() -> str: |
| 22 | + """A simple ping tool""" |
| 23 | + return "pong" |
| 24 | + |
| 25 | + |
| 26 | +# lifespan for managing the session manager |
| 27 | +@contextlib.asynccontextmanager |
| 28 | +async def lifespan(app: Starlette): |
| 29 | + """Gather any session managers for startup/shutdown. |
| 30 | + See streamable_starlette_mount.py for example of multiple mcp managers. |
| 31 | + """ |
| 32 | + async with mcp.session_manager.run(): |
| 33 | + yield |
| 34 | + |
| 35 | + |
| 36 | +"""Create the Starlette app and mount the MCP server. |
| 37 | +lifespan ensures the session manager is started/stopped with the app. |
| 38 | +session_manager references must only be made after streamable_http_app() |
| 39 | +""" |
| 40 | +app = Starlette( |
| 41 | + routes=[ |
| 42 | + # Mounted at /mcp |
| 43 | + Mount("/", app=mcp.streamable_http_app()), |
| 44 | + ], |
| 45 | + lifespan=lifespan, |
| 46 | +) |
| 47 | + |
| 48 | +if __name__ == "__main__": |
| 49 | + import uvicorn |
| 50 | + |
| 51 | + """Attach to another ASGI server LIFO |
| 52 | + ASGI chain: Uvicorn -> Starlette -> FastMCP |
| 53 | + Route: http://0.0.0.0:8000/mcp |
| 54 | + """ |
| 55 | + uvicorn.run(app, host="0.0.0.0", port=8000) |
0 commit comments