Skip to content

Commit 5edc93e

Browse files
docs: clarify streamable_http_path configuration when mounting servers
- Add StreamableHTTP servers section mirroring SSE servers structure - Start with simple mounting examples, then explain path composition - Document how to configure streamable_http_path for different scenarios - Add inline comments in Starlette mounting example This addresses confusion around endpoint paths when mounting FastMCP servers as sub-applications in ASGI frameworks.
1 parent 824ef8a commit 5edc93e

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,11 @@ app = Starlette(
11431143
],
11441144
lifespan=lifespan,
11451145
)
1146+
1147+
# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp
1148+
# To mount at the root of each path (e.g., /echo instead of /echo/mcp):
1149+
# echo_mcp.settings.streamable_http_path = "/"
1150+
# math_mcp.settings.streamable_http_path = "/"
11461151
```
11471152

11481153
_Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_
@@ -1166,6 +1171,89 @@ By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mo
11661171

11671172
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
11681173

1174+
#### StreamableHTTP servers
1175+
1176+
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.
1177+
1178+
<!-- snippet-source examples/snippets/servers/streamable_http_mounting.py -->
1179+
```python
1180+
"""
1181+
Example showing how to mount StreamableHTTP servers in Starlette applications.
1182+
1183+
Run from the repository root:
1184+
uvicorn examples.snippets.servers.streamable_http_mounting:app --reload
1185+
"""
1186+
1187+
from starlette.applications import Starlette
1188+
from starlette.routing import Host, Mount
1189+
1190+
from mcp.server.fastmcp import FastMCP
1191+
1192+
# Basic example - mounting at root
1193+
mcp = FastMCP("My App")
1194+
1195+
1196+
@mcp.tool()
1197+
def hello() -> str:
1198+
"""A simple hello tool"""
1199+
return "Hello from MCP!"
1200+
1201+
1202+
# Mount the StreamableHTTP server to the existing ASGI server
1203+
app = Starlette(
1204+
routes=[
1205+
Mount("/", app=mcp.streamable_http_app()),
1206+
]
1207+
)
1208+
1209+
# or dynamically mount as host
1210+
app.router.routes.append(Host("mcp.acme.corp", app=mcp.streamable_http_app()))
1211+
1212+
# Advanced example - multiple servers with path configuration
1213+
# Create multiple MCP servers
1214+
api_mcp = FastMCP("API Server")
1215+
chat_mcp = FastMCP("Chat Server")
1216+
1217+
1218+
@api_mcp.tool()
1219+
def api_status() -> str:
1220+
"""Get API status"""
1221+
return "API is running"
1222+
1223+
1224+
@chat_mcp.tool()
1225+
def send_message(message: str) -> str:
1226+
"""Send a chat message"""
1227+
return f"Message sent: {message}"
1228+
1229+
1230+
# Default behavior: endpoints will be at /api/mcp and /chat/mcp
1231+
default_app = Starlette(
1232+
routes=[
1233+
Mount("/api", app=api_mcp.streamable_http_app()),
1234+
Mount("/chat", app=chat_mcp.streamable_http_app()),
1235+
]
1236+
)
1237+
1238+
# To mount at the root of each path (e.g., /api instead of /api/mcp):
1239+
# Configure streamable_http_path before mounting
1240+
api_mcp.settings.streamable_http_path = "/"
1241+
chat_mcp.settings.streamable_http_path = "/"
1242+
1243+
configured_app = Starlette(
1244+
routes=[
1245+
Mount("/api", app=api_mcp.streamable_http_app()),
1246+
Mount("/chat", app=chat_mcp.streamable_http_app()),
1247+
]
1248+
)
1249+
1250+
# Or configure during initialization
1251+
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
1252+
```
1253+
1254+
_Full example: [examples/snippets/servers/streamable_http_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_mounting.py)_
1255+
<!-- /snippet-source -->
1256+
11691257
#### SSE servers
11701258

11711259
> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http).
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Example showing how to mount StreamableHTTP servers in Starlette applications.
3+
4+
Run from the repository root:
5+
uvicorn examples.snippets.servers.streamable_http_mounting:app --reload
6+
"""
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Host, Mount
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Basic example - mounting at root
14+
mcp = FastMCP("My App")
15+
16+
17+
@mcp.tool()
18+
def hello() -> str:
19+
"""A simple hello tool"""
20+
return "Hello from MCP!"
21+
22+
23+
# Mount the StreamableHTTP server to the existing ASGI server
24+
app = Starlette(
25+
routes=[
26+
Mount("/", app=mcp.streamable_http_app()),
27+
]
28+
)
29+
30+
# or dynamically mount as host
31+
app.router.routes.append(Host("mcp.acme.corp", app=mcp.streamable_http_app()))
32+
33+
# Advanced example - multiple servers with path configuration
34+
# Create multiple MCP servers
35+
api_mcp = FastMCP("API Server")
36+
chat_mcp = FastMCP("Chat Server")
37+
38+
39+
@api_mcp.tool()
40+
def api_status() -> str:
41+
"""Get API status"""
42+
return "API is running"
43+
44+
45+
@chat_mcp.tool()
46+
def send_message(message: str) -> str:
47+
"""Send a chat message"""
48+
return f"Message sent: {message}"
49+
50+
51+
# Default behavior: endpoints will be at /api/mcp and /chat/mcp
52+
default_app = Starlette(
53+
routes=[
54+
Mount("/api", app=api_mcp.streamable_http_app()),
55+
Mount("/chat", app=chat_mcp.streamable_http_app()),
56+
]
57+
)
58+
59+
# To mount at the root of each path (e.g., /api instead of /api/mcp):
60+
# Configure streamable_http_path before mounting
61+
api_mcp.settings.streamable_http_path = "/"
62+
chat_mcp.settings.streamable_http_path = "/"
63+
64+
configured_app = Starlette(
65+
routes=[
66+
Mount("/api", app=api_mcp.streamable_http_app()),
67+
Mount("/chat", app=chat_mcp.streamable_http_app()),
68+
]
69+
)
70+
71+
# Or configure during initialization
72+
mcp_at_root = FastMCP("My Server", streamable_http_path="/")

examples/snippets/servers/streamable_starlette_mount.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ async def lifespan(app: Starlette):
4747
],
4848
lifespan=lifespan,
4949
)
50+
51+
# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp
52+
# To mount at the root of each path (e.g., /echo instead of /echo/mcp):
53+
# echo_mcp.settings.streamable_http_path = "/"
54+
# math_mcp.settings.streamable_http_path = "/"

0 commit comments

Comments
 (0)