diff --git a/README.md b/README.md index 993b6006b..e738c94e3 100644 --- a/README.md +++ b/README.md @@ -979,6 +979,11 @@ app = Starlette( ], lifespan=lifespan, ) + +# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp +# To mount at the root of each path (e.g., /echo instead of /echo/mcp): +# echo_mcp.settings.streamable_http_path = "/" +# math_mcp.settings.streamable_http_path = "/" ``` _Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_ @@ -1002,6 +1007,172 @@ By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mo For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes). +#### StreamableHTTP servers + +You can mount the StreamableHTTP server to an existing ASGI server using the `streamable_http_app` method. This allows you to integrate the StreamableHTTP server with other ASGI applications. + +##### Basic mounting + + +```python +""" +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 +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("My App") + + +@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()), + ] +) +``` + +_Full example: [examples/snippets/servers/streamable_http_basic_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_basic_mounting.py)_ + + +##### Host-based routing + + +```python +""" +Example showing how to mount StreamableHTTP server using Host-based routing. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Host + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("MCP Host App") + + +@mcp.tool() +def domain_info() -> str: + """Get domain-specific information""" + return "This is served from mcp.acme.corp" + + +# Mount using Host-based routing +app = Starlette( + routes=[ + Host("mcp.acme.corp", app=mcp.streamable_http_app()), + ] +) +``` + +_Full example: [examples/snippets/servers/streamable_http_host_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_host_mounting.py)_ + + +##### Multiple servers with path configuration + + +```python +""" +Example showing how to mount multiple StreamableHTTP servers with path configuration. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create multiple MCP servers +api_mcp = FastMCP("API Server") +chat_mcp = FastMCP("Chat Server") + + +@api_mcp.tool() +def api_status() -> str: + """Get API status""" + return "API is running" + + +@chat_mcp.tool() +def send_message(message: str) -> str: + """Send a chat message""" + return f"Message sent: {message}" + + +# Configure servers to mount at the root of each path +# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp +api_mcp.settings.streamable_http_path = "/" +chat_mcp.settings.streamable_http_path = "/" + +# Mount the servers +app = Starlette( + routes=[ + Mount("/api", app=api_mcp.streamable_http_app()), + Mount("/chat", app=chat_mcp.streamable_http_app()), + ] +) +``` + +_Full example: [examples/snippets/servers/streamable_http_multiple_servers.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_multiple_servers.py)_ + + +##### Path configuration at initialization + + +```python +""" +Example showing path configuration during FastMCP initialization. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_path_config:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Configure streamable_http_path during initialization +# This server will mount at the root of wherever it's mounted +mcp_at_root = FastMCP("My Server", streamable_http_path="/") + + +@mcp_at_root.tool() +def process_data(data: str) -> str: + """Process some data""" + return f"Processed: {data}" + + +# Mount at /process - endpoints will be at /process instead of /process/mcp +app = Starlette( + routes=[ + Mount("/process", app=mcp_at_root.streamable_http_app()), + ] +) +``` + +_Full example: [examples/snippets/servers/streamable_http_path_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_path_config.py)_ + + #### SSE servers > **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). diff --git a/examples/snippets/servers/streamable_http_basic_mounting.py b/examples/snippets/servers/streamable_http_basic_mounting.py new file mode 100644 index 000000000..abcc0e572 --- /dev/null +++ b/examples/snippets/servers/streamable_http_basic_mounting.py @@ -0,0 +1,28 @@ +""" +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 +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("My App") + + +@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()), + ] +) diff --git a/examples/snippets/servers/streamable_http_host_mounting.py b/examples/snippets/servers/streamable_http_host_mounting.py new file mode 100644 index 000000000..d48558cc8 --- /dev/null +++ b/examples/snippets/servers/streamable_http_host_mounting.py @@ -0,0 +1,28 @@ +""" +Example showing how to mount StreamableHTTP server using Host-based routing. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Host + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("MCP Host App") + + +@mcp.tool() +def domain_info() -> str: + """Get domain-specific information""" + return "This is served from mcp.acme.corp" + + +# Mount using Host-based routing +app = Starlette( + routes=[ + Host("mcp.acme.corp", app=mcp.streamable_http_app()), + ] +) diff --git a/examples/snippets/servers/streamable_http_multiple_servers.py b/examples/snippets/servers/streamable_http_multiple_servers.py new file mode 100644 index 000000000..df347b7b3 --- /dev/null +++ b/examples/snippets/servers/streamable_http_multiple_servers.py @@ -0,0 +1,41 @@ +""" +Example showing how to mount multiple StreamableHTTP servers with path configuration. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create multiple MCP servers +api_mcp = FastMCP("API Server") +chat_mcp = FastMCP("Chat Server") + + +@api_mcp.tool() +def api_status() -> str: + """Get API status""" + return "API is running" + + +@chat_mcp.tool() +def send_message(message: str) -> str: + """Send a chat message""" + return f"Message sent: {message}" + + +# Configure servers to mount at the root of each path +# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp +api_mcp.settings.streamable_http_path = "/" +chat_mcp.settings.streamable_http_path = "/" + +# Mount the servers +app = Starlette( + routes=[ + Mount("/api", app=api_mcp.streamable_http_app()), + Mount("/chat", app=chat_mcp.streamable_http_app()), + ] +) diff --git a/examples/snippets/servers/streamable_http_path_config.py b/examples/snippets/servers/streamable_http_path_config.py new file mode 100644 index 000000000..71228423e --- /dev/null +++ b/examples/snippets/servers/streamable_http_path_config.py @@ -0,0 +1,29 @@ +""" +Example showing path configuration during FastMCP initialization. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_path_config:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Configure streamable_http_path during initialization +# This server will mount at the root of wherever it's mounted +mcp_at_root = FastMCP("My Server", streamable_http_path="/") + + +@mcp_at_root.tool() +def process_data(data: str) -> str: + """Process some data""" + return f"Processed: {data}" + + +# Mount at /process - endpoints will be at /process instead of /process/mcp +app = Starlette( + routes=[ + Mount("/process", app=mcp_at_root.streamable_http_app()), + ] +) diff --git a/examples/snippets/servers/streamable_starlette_mount.py b/examples/snippets/servers/streamable_starlette_mount.py index 19e41294b..57d2d2ea5 100644 --- a/examples/snippets/servers/streamable_starlette_mount.py +++ b/examples/snippets/servers/streamable_starlette_mount.py @@ -47,3 +47,8 @@ async def lifespan(app: Starlette): ], lifespan=lifespan, ) + +# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp +# To mount at the root of each path (e.g., /echo instead of /echo/mcp): +# echo_mcp.settings.streamable_http_path = "/" +# math_mcp.settings.streamable_http_path = "/"