Skip to content

Commit ff02c59

Browse files
docs: clarify streamable_http_path configuration when mounting servers (modelcontextprotocol#1172)
1 parent 824ef8a commit ff02c59

File tree

6 files changed

+302
-0
lines changed

6 files changed

+302
-0
lines changed

README.md

Lines changed: 171 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,172 @@ 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+
##### Basic mounting
1179+
1180+
<!-- snippet-source examples/snippets/servers/streamable_http_basic_mounting.py -->
1181+
```python
1182+
"""
1183+
Basic example showing how to mount StreamableHTTP server in Starlette.
1184+
1185+
Run from the repository root:
1186+
uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload
1187+
"""
1188+
1189+
from starlette.applications import Starlette
1190+
from starlette.routing import Mount
1191+
1192+
from mcp.server.fastmcp import FastMCP
1193+
1194+
# Create MCP server
1195+
mcp = FastMCP("My App")
1196+
1197+
1198+
@mcp.tool()
1199+
def hello() -> str:
1200+
"""A simple hello tool"""
1201+
return "Hello from MCP!"
1202+
1203+
1204+
# Mount the StreamableHTTP server to the existing ASGI server
1205+
app = Starlette(
1206+
routes=[
1207+
Mount("/", app=mcp.streamable_http_app()),
1208+
]
1209+
)
1210+
```
1211+
1212+
_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)_
1213+
<!-- /snippet-source -->
1214+
1215+
##### Host-based routing
1216+
1217+
<!-- snippet-source examples/snippets/servers/streamable_http_host_mounting.py -->
1218+
```python
1219+
"""
1220+
Example showing how to mount StreamableHTTP server using Host-based routing.
1221+
1222+
Run from the repository root:
1223+
uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload
1224+
"""
1225+
1226+
from starlette.applications import Starlette
1227+
from starlette.routing import Host
1228+
1229+
from mcp.server.fastmcp import FastMCP
1230+
1231+
# Create MCP server
1232+
mcp = FastMCP("MCP Host App")
1233+
1234+
1235+
@mcp.tool()
1236+
def domain_info() -> str:
1237+
"""Get domain-specific information"""
1238+
return "This is served from mcp.acme.corp"
1239+
1240+
1241+
# Mount using Host-based routing
1242+
app = Starlette(
1243+
routes=[
1244+
Host("mcp.acme.corp", app=mcp.streamable_http_app()),
1245+
]
1246+
)
1247+
```
1248+
1249+
_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)_
1250+
<!-- /snippet-source -->
1251+
1252+
##### Multiple servers with path configuration
1253+
1254+
<!-- snippet-source examples/snippets/servers/streamable_http_multiple_servers.py -->
1255+
```python
1256+
"""
1257+
Example showing how to mount multiple StreamableHTTP servers with path configuration.
1258+
1259+
Run from the repository root:
1260+
uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload
1261+
"""
1262+
1263+
from starlette.applications import Starlette
1264+
from starlette.routing import Mount
1265+
1266+
from mcp.server.fastmcp import FastMCP
1267+
1268+
# Create multiple MCP servers
1269+
api_mcp = FastMCP("API Server")
1270+
chat_mcp = FastMCP("Chat Server")
1271+
1272+
1273+
@api_mcp.tool()
1274+
def api_status() -> str:
1275+
"""Get API status"""
1276+
return "API is running"
1277+
1278+
1279+
@chat_mcp.tool()
1280+
def send_message(message: str) -> str:
1281+
"""Send a chat message"""
1282+
return f"Message sent: {message}"
1283+
1284+
1285+
# Configure servers to mount at the root of each path
1286+
# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp
1287+
api_mcp.settings.streamable_http_path = "/"
1288+
chat_mcp.settings.streamable_http_path = "/"
1289+
1290+
# Mount the servers
1291+
app = Starlette(
1292+
routes=[
1293+
Mount("/api", app=api_mcp.streamable_http_app()),
1294+
Mount("/chat", app=chat_mcp.streamable_http_app()),
1295+
]
1296+
)
1297+
```
1298+
1299+
_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)_
1300+
<!-- /snippet-source -->
1301+
1302+
##### Path configuration at initialization
1303+
1304+
<!-- snippet-source examples/snippets/servers/streamable_http_path_config.py -->
1305+
```python
1306+
"""
1307+
Example showing path configuration during FastMCP initialization.
1308+
1309+
Run from the repository root:
1310+
uvicorn examples.snippets.servers.streamable_http_path_config:app --reload
1311+
"""
1312+
1313+
from starlette.applications import Starlette
1314+
from starlette.routing import Mount
1315+
1316+
from mcp.server.fastmcp import FastMCP
1317+
1318+
# Configure streamable_http_path during initialization
1319+
# This server will mount at the root of wherever it's mounted
1320+
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
1321+
1322+
1323+
@mcp_at_root.tool()
1324+
def process_data(data: str) -> str:
1325+
"""Process some data"""
1326+
return f"Processed: {data}"
1327+
1328+
1329+
# Mount at /process - endpoints will be at /process instead of /process/mcp
1330+
app = Starlette(
1331+
routes=[
1332+
Mount("/process", app=mcp_at_root.streamable_http_app()),
1333+
]
1334+
)
1335+
```
1336+
1337+
_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)_
1338+
<!-- /snippet-source -->
1339+
11691340
#### SSE servers
11701341

11711342
> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http).
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Basic example showing how to mount StreamableHTTP server in Starlette.
3+
4+
Run from the repository root:
5+
uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload
6+
"""
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Mount
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Create MCP server
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+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Example showing how to mount StreamableHTTP server using Host-based routing.
3+
4+
Run from the repository root:
5+
uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload
6+
"""
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Host
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Create MCP server
14+
mcp = FastMCP("MCP Host App")
15+
16+
17+
@mcp.tool()
18+
def domain_info() -> str:
19+
"""Get domain-specific information"""
20+
return "This is served from mcp.acme.corp"
21+
22+
23+
# Mount using Host-based routing
24+
app = Starlette(
25+
routes=[
26+
Host("mcp.acme.corp", app=mcp.streamable_http_app()),
27+
]
28+
)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
Example showing how to mount multiple StreamableHTTP servers with path configuration.
3+
4+
Run from the repository root:
5+
uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload
6+
"""
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Mount
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Create multiple MCP servers
14+
api_mcp = FastMCP("API Server")
15+
chat_mcp = FastMCP("Chat Server")
16+
17+
18+
@api_mcp.tool()
19+
def api_status() -> str:
20+
"""Get API status"""
21+
return "API is running"
22+
23+
24+
@chat_mcp.tool()
25+
def send_message(message: str) -> str:
26+
"""Send a chat message"""
27+
return f"Message sent: {message}"
28+
29+
30+
# Configure servers to mount at the root of each path
31+
# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp
32+
api_mcp.settings.streamable_http_path = "/"
33+
chat_mcp.settings.streamable_http_path = "/"
34+
35+
# Mount the servers
36+
app = Starlette(
37+
routes=[
38+
Mount("/api", app=api_mcp.streamable_http_app()),
39+
Mount("/chat", app=chat_mcp.streamable_http_app()),
40+
]
41+
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Example showing path configuration during FastMCP initialization.
3+
4+
Run from the repository root:
5+
uvicorn examples.snippets.servers.streamable_http_path_config:app --reload
6+
"""
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Mount
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Configure streamable_http_path during initialization
14+
# This server will mount at the root of wherever it's mounted
15+
mcp_at_root = FastMCP("My Server", streamable_http_path="/")
16+
17+
18+
@mcp_at_root.tool()
19+
def process_data(data: str) -> str:
20+
"""Process some data"""
21+
return f"Processed: {data}"
22+
23+
24+
# Mount at /process - endpoints will be at /process instead of /process/mcp
25+
app = Starlette(
26+
routes=[
27+
Mount("/process", app=mcp_at_root.streamable_http_app()),
28+
]
29+
)

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)