Skip to content

docs: clarify streamable_http_path configuration when mounting servers #1172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)_
Expand All @@ -1002,6 +1007,89 @@ 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.

<!-- snippet-source examples/snippets/servers/streamable_http_mounting.py -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is supposed to be a single big file. There are many examples with different applications here. Can we split them?

```python
"""
Example showing how to mount StreamableHTTP servers in Starlette applications.

Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_mounting:app --reload
"""

from starlette.applications import Starlette
from starlette.routing import Host, Mount

from mcp.server.fastmcp import FastMCP

# Basic example - mounting at root
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()),
]
)

# or dynamically mount as host
app.router.routes.append(Host("mcp.acme.corp", app=mcp.streamable_http_app()))
Comment on lines +1045 to +1046
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include the Host above please. No one should include the routes manually as this line.


# Advanced example - multiple servers with path configuration
# 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}"


# Default behavior: endpoints will be at /api/mcp and /chat/mcp
default_app = Starlette(
routes=[
Mount("/api", app=api_mcp.streamable_http_app()),
Mount("/chat", app=chat_mcp.streamable_http_app()),
]
)

# To mount at the root of each path (e.g., /api instead of /api/mcp):
# Configure streamable_http_path before mounting
api_mcp.settings.streamable_http_path = "/"
chat_mcp.settings.streamable_http_path = "/"

configured_app = Starlette(
routes=[
Mount("/api", app=api_mcp.streamable_http_app()),
Mount("/chat", app=chat_mcp.streamable_http_app()),
]
)

# Or configure during initialization
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
```

_Full example: [examples/snippets/servers/streamable_http_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_mounting.py)_
<!-- /snippet-source -->

#### SSE servers

> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http).
Expand Down
72 changes: 72 additions & 0 deletions examples/snippets/servers/streamable_http_mounting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Example showing how to mount StreamableHTTP servers in Starlette applications.

Run from the repository root:
uvicorn examples.snippets.servers.streamable_http_mounting:app --reload
"""

from starlette.applications import Starlette
from starlette.routing import Host, Mount

from mcp.server.fastmcp import FastMCP

# Basic example - mounting at root
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()),
]
)

# or dynamically mount as host
app.router.routes.append(Host("mcp.acme.corp", app=mcp.streamable_http_app()))

# Advanced example - multiple servers with path configuration
# 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}"


# Default behavior: endpoints will be at /api/mcp and /chat/mcp
default_app = Starlette(
routes=[
Mount("/api", app=api_mcp.streamable_http_app()),
Mount("/chat", app=chat_mcp.streamable_http_app()),
]
)

# To mount at the root of each path (e.g., /api instead of /api/mcp):
# Configure streamable_http_path before mounting
api_mcp.settings.streamable_http_path = "/"
chat_mcp.settings.streamable_http_path = "/"

configured_app = Starlette(
routes=[
Mount("/api", app=api_mcp.streamable_http_app()),
Mount("/chat", app=chat_mcp.streamable_http_app()),
]
)

# Or configure during initialization
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
5 changes: 5 additions & 0 deletions examples/snippets/servers/streamable_starlette_mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "/"
Loading