Documentation on mounting to existing ASGI server is missing information
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
Overview
PR #1172 is missing information.
Minimal Working Example
take a slightly modified script from here and run it with uv run --script main.py
# /// script # requires-python = ">=3.12" # dependencies = [ # "mcp>=1.12", # "starlette", # "uvicorn", # ] # /// """ Basic example showing how to mount StreamableHTTP server in Starlette. Run from the repository root: uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload """ import asyncio from mcp.server.fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount # Create MCP server mcp = FastMCP("My App", stateless_http=True) @mcp.tool() def hello() -> str: """A simple hello tool""" return "Hello from MCP!" # Mount the StreamableHTTP server to the existing ASGI server app = Starlette( routes=[ Mount("/", app=mcp.streamable_http_app()), ] ) if __name__ == "__main__": import asyncio import uvicorn asyncio.create_task(mcp.run(transport="streamable-http")) asyncio.run(uvicorn.run(app, host="0.0.0.0", port=8000))
and test it with the following bash script (bash test_mcp_server.sh)
#!/usr/bin/env bash MCP_SERVER_PORT=8000 MCP_SERVER_HOST=0.0.0.0 # for mcp service # first initialize it curl -X POST "http://${MCP_SERVER_HOST}:${MCP_SERVER_PORT}/mcp" \ -H "Content-Type: application/json" \ -H "Accept: application/json,text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": { "tools": {}, "resources": {}, "prompts": {} }, "clientInfo": { "name": "test-client", "version": "1.0.0" } } }' echo -e "\nInitialized" curl -X POST "http://${MCP_SERVER_HOST}:${MCP_SERVER_PORT}/mcp" \ -H "Content-Type: application/json" \ -H "Accept: application/json,text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }' echo -e "\nTools listed" curl -X POST http://${MCP_SERVER_HOST}:${MCP_SERVER_PORT}/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json,text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "hello", "arguments": {} } }' echo -e "\nTools called"
Result:
- with
asyncio.create_task(...)removed,bash test_mcp_server.shreturnsInternal Server Error. the mcp server reports
lib/python3.12/site-packages/mcp/server/streamable_http_manager.py", line 138, in handle_request raise RuntimeError("Task group is not initialized. Make sure to use run().") RuntimeError: Task group is not initialized. Make sure to use run().
- with
asycnio.create_task(...)added,bash test_mcp_server.shreturns expected result.
bash test_echo_server.sh
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"My App","version":"1.17.0"}}}
Initialized
event: message
data: {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"hello","description":"A simple hello tool","inputSchema":{"properties":{},"title":"helloArguments","type":"object"},"outputSchema":{"properties":{"result":{"title":"Result","type":"string"}},"required":["result"],"title":"helloOutput","type":"object"}}]}}
Tools listed
event: message
data: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"Hello from MCP!"}],"structuredContent":{"result":"Hello from MCP!"},"isError":false}}
Tools calledSuggested Fix
I can submit a PR to update all related snippets under this folder if this is indeed an issue.
Example Code
# /// script # requires-python = ">=3.12" # dependencies = [ # "mcp>=1.12", # "starlette", # "uvicorn", # ] # /// """ Basic example showing how to mount StreamableHTTP server in Starlette. Run from the repository root: uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload """ import asyncio from mcp.server.fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount # Create MCP server mcp = FastMCP("My App", stateless_http=True) @mcp.tool() def hello() -> str: """A simple hello tool""" return "Hello from MCP!" # Mount the StreamableHTTP server to the existing ASGI server app = Starlette( routes=[ Mount("/", app=mcp.streamable_http_app()), ] ) if __name__ == "__main__": import asyncio import uvicorn # asyncio.create_task(mcp.run(transport="streamable-http")) asyncio.run(uvicorn.run(app, host="0.0.0.0", port=8000))