Skip to content

Commit e975d05

Browse files
authored
README - replace code snippets with examples - streamable http (#1155)
1 parent 0b4ce00 commit e975d05

File tree

7 files changed

+186
-73
lines changed

7 files changed

+186
-73
lines changed

README.md

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -532,9 +532,7 @@ Client usage:
532532

533533
<!-- snippet-source examples/snippets/clients/completion_client.py -->
534534
```python
535-
"""MCP client example showing completion usage.
536-
537-
This example demonstrates how to use the completion feature in MCP clients.
535+
"""
538536
cd to the `examples/snippets` directory and run:
539537
uv run completion-client
540538
"""
@@ -863,72 +861,99 @@ Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMC
863861

864862
> **Note**: Streamable HTTP transport is superseding SSE transport for production deployments.
865863
864+
<!-- snippet-source examples/snippets/servers/streamable_config.py -->
866865
```python
866+
"""
867+
Run from the repository root:
868+
uv run examples/snippets/servers/streamable_config.py
869+
"""
870+
867871
from mcp.server.fastmcp import FastMCP
868872

869873
# Stateful server (maintains session state)
870874
mcp = FastMCP("StatefulServer")
871875

876+
# Other configuration options:
872877
# Stateless server (no session persistence)
873-
mcp = FastMCP("StatelessServer", stateless_http=True)
878+
# mcp = FastMCP("StatelessServer", stateless_http=True)
874879

875880
# Stateless server (no session persistence, no sse stream with supported client)
876-
mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
881+
# mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
882+
883+
884+
# Add a simple tool to demonstrate the server
885+
@mcp.tool()
886+
def greet(name: str = "World") -> str:
887+
"""Greet someone by name."""
888+
return f"Hello, {name}!"
889+
877890

878891
# Run server with streamable_http transport
879-
mcp.run(transport="streamable-http")
892+
if __name__ == "__main__":
893+
mcp.run(transport="streamable-http")
880894
```
881895

882-
You can mount multiple FastMCP servers in a FastAPI application:
896+
_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_
897+
<!-- /snippet-source -->
898+
899+
You can mount multiple FastMCP servers in a Starlette application:
883900

901+
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
884902
```python
885-
# echo.py
903+
"""
904+
Run from the repository root:
905+
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
906+
"""
907+
908+
import contextlib
909+
910+
from starlette.applications import Starlette
911+
from starlette.routing import Mount
912+
886913
from mcp.server.fastmcp import FastMCP
887914

888-
mcp = FastMCP(name="EchoServer", stateless_http=True)
915+
# Create the Echo server
916+
echo_mcp = FastMCP(name="EchoServer", stateless_http=True)
889917

890918

891-
@mcp.tool()
919+
@echo_mcp.tool()
892920
def echo(message: str) -> str:
893921
"""A simple echo tool"""
894922
return f"Echo: {message}"
895-
```
896923

897-
```python
898-
# math.py
899-
from mcp.server.fastmcp import FastMCP
900924

901-
mcp = FastMCP(name="MathServer", stateless_http=True)
925+
# Create the Math server
926+
math_mcp = FastMCP(name="MathServer", stateless_http=True)
902927

903928

904-
@mcp.tool()
929+
@math_mcp.tool()
905930
def add_two(n: int) -> int:
906931
"""Tool to add two to the input"""
907932
return n + 2
908-
```
909-
910-
```python
911-
# main.py
912-
import contextlib
913-
from fastapi import FastAPI
914-
from mcp.echo import echo
915-
from mcp.math import math
916933

917934

918935
# Create a combined lifespan to manage both session managers
919936
@contextlib.asynccontextmanager
920-
async def lifespan(app: FastAPI):
937+
async def lifespan(app: Starlette):
921938
async with contextlib.AsyncExitStack() as stack:
922-
await stack.enter_async_context(echo.mcp.session_manager.run())
923-
await stack.enter_async_context(math.mcp.session_manager.run())
939+
await stack.enter_async_context(echo_mcp.session_manager.run())
940+
await stack.enter_async_context(math_mcp.session_manager.run())
924941
yield
925942

926943

927-
app = FastAPI(lifespan=lifespan)
928-
app.mount("/echo", echo.mcp.streamable_http_app())
929-
app.mount("/math", math.mcp.streamable_http_app())
944+
# Create the Starlette app and mount the MCP servers
945+
app = Starlette(
946+
routes=[
947+
Mount("/echo", echo_mcp.streamable_http_app()),
948+
Mount("/math", math_mcp.streamable_http_app()),
949+
],
950+
lifespan=lifespan,
951+
)
930952
```
931953

954+
_Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_
955+
<!-- /snippet-source -->
956+
932957
For low level server with Streamable HTTP implementations, see:
933958

934959
- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/)
@@ -945,26 +970,6 @@ The streamable HTTP transport supports:
945970

946971
By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mounted at `/mcp`. You can customize these paths using the methods described below.
947972

948-
#### Streamable HTTP servers
949-
950-
The following example shows how to use `streamable_http_app()`, a method that returns a `Starlette` application object.
951-
You can then append additional routes to that application as needed.
952-
953-
```python
954-
mcp = FastMCP("My App")
955-
956-
app = mcp.streamable_http_app()
957-
# Additional non-MCP routes can be added like so:
958-
# from starlette.routing import Route
959-
# app.router.routes.append(Route("/", endpoint=other_route_function))
960-
```
961-
962-
To customize the route from the default of "/mcp", either specify the `streamable_http_path` option for the `FastMCP` constructor,
963-
or set `FASTMCP_STREAMABLE_HTTP_PATH` environment variable.
964-
965-
Note that in Starlette and FastAPI (which is based on Starlette), the "/mcp" route will redirect to "/mcp/",
966-
so you may need to use "/mcp/" when pointing MCP clients at your servers.
967-
968973
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
969974

970975
#### SSE servers
@@ -1336,9 +1341,7 @@ The SDK provides a high-level client interface for connecting to MCP servers usi
13361341

13371342
<!-- snippet-source examples/snippets/clients/stdio_client.py -->
13381343
```python
1339-
"""MCP client example using stdio transport.
1340-
1341-
This is a documentation example showing how to write an MCP client.
1344+
"""
13421345
cd to the `examples/snippets/clients` directory and run:
13431346
uv run client
13441347
"""
@@ -1428,14 +1431,22 @@ _Full example: [examples/snippets/clients/stdio_client.py](https://github.com/mo
14281431

14291432
Clients can also connect using [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http):
14301433

1434+
<!-- snippet-source examples/snippets/clients/streamable_basic.py -->
14311435
```python
1432-
from mcp.client.streamable_http import streamablehttp_client
1436+
"""
1437+
Run from the repository root:
1438+
uv run examples/snippets/clients/streamable_basic.py
1439+
"""
1440+
1441+
import asyncio
1442+
14331443
from mcp import ClientSession
1444+
from mcp.client.streamable_http import streamablehttp_client
14341445

14351446

14361447
async def main():
14371448
# Connect to a streamable HTTP server
1438-
async with streamablehttp_client("example/mcp") as (
1449+
async with streamablehttp_client("http://localhost:8000/mcp") as (
14391450
read_stream,
14401451
write_stream,
14411452
_,
@@ -1444,21 +1455,25 @@ async def main():
14441455
async with ClientSession(read_stream, write_stream) as session:
14451456
# Initialize the connection
14461457
await session.initialize()
1447-
# Call a tool
1448-
tool_result = await session.call_tool("echo", {"message": "hello"})
1458+
# List available tools
1459+
tools = await session.list_tools()
1460+
print(f"Available tools: {[tool.name for tool in tools.tools]}")
1461+
1462+
1463+
if __name__ == "__main__":
1464+
asyncio.run(main())
14491465
```
14501466

1467+
_Full example: [examples/snippets/clients/streamable_basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/streamable_basic.py)_
1468+
<!-- /snippet-source -->
1469+
14511470
### Client Display Utilities
14521471

14531472
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
14541473

14551474
<!-- snippet-source examples/snippets/clients/display_utilities.py -->
14561475
```python
1457-
"""Client display utilities example.
1458-
1459-
This example shows how to use the SDK's display utilities to show
1460-
human-readable names for tools, resources, and prompts.
1461-
1476+
"""
14621477
cd to the `examples/snippets` directory and run:
14631478
uv run display-utilities-client
14641479
"""

examples/snippets/clients/completion_client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""MCP client example showing completion usage.
2-
3-
This example demonstrates how to use the completion feature in MCP clients.
1+
"""
42
cd to the `examples/snippets` directory and run:
53
uv run completion-client
64
"""

examples/snippets/clients/display_utilities.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
"""Client display utilities example.
2-
3-
This example shows how to use the SDK's display utilities to show
4-
human-readable names for tools, resources, and prompts.
5-
1+
"""
62
cd to the `examples/snippets` directory and run:
73
uv run display-utilities-client
84
"""

examples/snippets/clients/stdio_client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""MCP client example using stdio transport.
2-
3-
This is a documentation example showing how to write an MCP client.
1+
"""
42
cd to the `examples/snippets/clients` directory and run:
53
uv run client
64
"""
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Run from the repository root:
3+
uv run examples/snippets/clients/streamable_basic.py
4+
"""
5+
6+
import asyncio
7+
8+
from mcp import ClientSession
9+
from mcp.client.streamable_http import streamablehttp_client
10+
11+
12+
async def main():
13+
# Connect to a streamable HTTP server
14+
async with streamablehttp_client("http://localhost:8000/mcp") as (
15+
read_stream,
16+
write_stream,
17+
_,
18+
):
19+
# Create a session using the client streams
20+
async with ClientSession(read_stream, write_stream) as session:
21+
# Initialize the connection
22+
await session.initialize()
23+
# List available tools
24+
tools = await session.list_tools()
25+
print(f"Available tools: {[tool.name for tool in tools.tools]}")
26+
27+
28+
if __name__ == "__main__":
29+
asyncio.run(main())
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Run from the repository root:
3+
uv run examples/snippets/servers/streamable_config.py
4+
"""
5+
6+
from mcp.server.fastmcp import FastMCP
7+
8+
# Stateful server (maintains session state)
9+
mcp = FastMCP("StatefulServer")
10+
11+
# Other configuration options:
12+
# Stateless server (no session persistence)
13+
# mcp = FastMCP("StatelessServer", stateless_http=True)
14+
15+
# Stateless server (no session persistence, no sse stream with supported client)
16+
# mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
17+
18+
19+
# Add a simple tool to demonstrate the server
20+
@mcp.tool()
21+
def greet(name: str = "World") -> str:
22+
"""Greet someone by name."""
23+
return f"Hello, {name}!"
24+
25+
26+
# Run server with streamable_http transport
27+
if __name__ == "__main__":
28+
mcp.run(transport="streamable-http")
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Run from the repository root:
3+
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
4+
"""
5+
6+
import contextlib
7+
8+
from starlette.applications import Starlette
9+
from starlette.routing import Mount
10+
11+
from mcp.server.fastmcp import FastMCP
12+
13+
# Create the Echo server
14+
echo_mcp = FastMCP(name="EchoServer", stateless_http=True)
15+
16+
17+
@echo_mcp.tool()
18+
def echo(message: str) -> str:
19+
"""A simple echo tool"""
20+
return f"Echo: {message}"
21+
22+
23+
# Create the Math server
24+
math_mcp = FastMCP(name="MathServer", stateless_http=True)
25+
26+
27+
@math_mcp.tool()
28+
def add_two(n: int) -> int:
29+
"""Tool to add two to the input"""
30+
return n + 2
31+
32+
33+
# Create a combined lifespan to manage both session managers
34+
@contextlib.asynccontextmanager
35+
async def lifespan(app: Starlette):
36+
async with contextlib.AsyncExitStack() as stack:
37+
await stack.enter_async_context(echo_mcp.session_manager.run())
38+
await stack.enter_async_context(math_mcp.session_manager.run())
39+
yield
40+
41+
42+
# Create the Starlette app and mount the MCP servers
43+
app = Starlette(
44+
routes=[
45+
Mount("/echo", echo_mcp.streamable_http_app()),
46+
Mount("/math", math_mcp.streamable_http_app()),
47+
],
48+
lifespan=lifespan,
49+
)

0 commit comments

Comments
 (0)