Documentation on mounting to existing ASGI server is missing information

Initial Checks

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:

  1. with asyncio.create_task(...) removed, bash test_mcp_server.sh returns Internal 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().
  1. with asycnio.create_task(...) added, bash test_mcp_server.sh returns 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 called

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

Python & MCP Python SDK