Skip to content

Commit 9392faa

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 0b1b52b commit 9392faa

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
@@ -979,6 +979,11 @@ app = Starlette(
979979
],
980980
lifespan=lifespan,
981981
)
982+
983+
# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp
984+
# To mount at the root of each path (e.g., /echo instead of /echo/mcp):
985+
# echo_mcp.settings.streamable_http_path = "/"
986+
# math_mcp.settings.streamable_http_path = "/"
982987
```
983988

984989
_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,89 @@ By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mo
10021007

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

1010+
#### StreamableHTTP servers
1011+
1012+
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.
1013+
1014+
<!-- snippet-source examples/snippets/servers/streamable_http_mounting.py -->
1015+
```python
1016+
"""
1017+
Example showing how to mount StreamableHTTP servers in Starlette applications.
1018+
1019+
Run from the repository root:
1020+
uvicorn examples.snippets.servers.streamable_http_mounting:app --reload
1021+
"""
1022+
1023+
from starlette.applications import Starlette
1024+
from starlette.routing import Host, Mount
1025+
1026+
from mcp.server.fastmcp import FastMCP
1027+
1028+
# Basic example - mounting at root
1029+
mcp = FastMCP("My App")
1030+
1031+
1032+
@mcp.tool()
1033+
def hello() -> str:
1034+
"""A simple hello tool"""
1035+
return "Hello from MCP!"
1036+
1037+
1038+
# Mount the StreamableHTTP server to the existing ASGI server
1039+
app = Starlette(
1040+
routes=[
1041+
Mount("/", app=mcp.streamable_http_app()),
1042+
]
1043+
)
1044+
1045+
# or dynamically mount as host
1046+
app.router.routes.append(Host("mcp.acme.corp", app=mcp.streamable_http_app()))
1047+
1048+
# Advanced example - multiple servers with path configuration
1049+
# Create multiple MCP servers
1050+
api_mcp = FastMCP("API Server")
1051+
chat_mcp = FastMCP("Chat Server")
1052+
1053+
1054+
@api_mcp.tool()
1055+
def api_status() -> str:
1056+
"""Get API status"""
1057+
return "API is running"
1058+
1059+
1060+
@chat_mcp.tool()
1061+
def send_message(message: str) -> str:
1062+
"""Send a chat message"""
1063+
return f"Message sent: {message}"
1064+
1065+
1066+
# Default behavior: endpoints will be at /api/mcp and /chat/mcp
1067+
default_app = Starlette(
1068+
routes=[
1069+
Mount("/api", app=api_mcp.streamable_http_app()),
1070+
Mount("/chat", app=chat_mcp.streamable_http_app()),
1071+
]
1072+
)
1073+
1074+
# To mount at the root of each path (e.g., /api instead of /api/mcp):
1075+
# Configure streamable_http_path before mounting
1076+
api_mcp.settings.streamable_http_path = "/"
1077+
chat_mcp.settings.streamable_http_path = "/"
1078+
1079+
configured_app = Starlette(
1080+
routes=[
1081+
Mount("/api", app=api_mcp.streamable_http_app()),
1082+
Mount("/chat", app=chat_mcp.streamable_http_app()),
1083+
]
1084+
)
1085+
1086+
# Or configure during initialization
1087+
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
1088+
```
1089+
1090+
_Full example: [examples/snippets/servers/streamable_http_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_mounting.py)_
1091+
<!-- /snippet-source -->
1092+
10051093
#### SSE servers
10061094

10071095
> **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)