README - replace code snippets with examples - streamable http (#1155)
This commit is contained in:
parent
0b4ce00be2
commit
e975d0550b
7 changed files with 186 additions and 73 deletions
141
README.md
141
README.md
|
|
@ -532,9 +532,7 @@ Client usage:
|
||||||
|
|
||||||
<!-- snippet-source examples/snippets/clients/completion_client.py -->
|
<!-- snippet-source examples/snippets/clients/completion_client.py -->
|
||||||
```python
|
```python
|
||||||
"""MCP client example showing completion usage.
|
"""
|
||||||
|
|
||||||
This example demonstrates how to use the completion feature in MCP clients.
|
|
||||||
cd to the `examples/snippets` directory and run:
|
cd to the `examples/snippets` directory and run:
|
||||||
uv run completion-client
|
uv run completion-client
|
||||||
"""
|
"""
|
||||||
|
|
@ -863,72 +861,99 @@ Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMC
|
||||||
|
|
||||||
> **Note**: Streamable HTTP transport is superseding SSE transport for production deployments.
|
> **Note**: Streamable HTTP transport is superseding SSE transport for production deployments.
|
||||||
|
|
||||||
|
<!-- snippet-source examples/snippets/servers/streamable_config.py -->
|
||||||
```python
|
```python
|
||||||
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uv run examples/snippets/servers/streamable_config.py
|
||||||
|
"""
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
# Stateful server (maintains session state)
|
# Stateful server (maintains session state)
|
||||||
mcp = FastMCP("StatefulServer")
|
mcp = FastMCP("StatefulServer")
|
||||||
|
|
||||||
|
# Other configuration options:
|
||||||
# Stateless server (no session persistence)
|
# Stateless server (no session persistence)
|
||||||
mcp = FastMCP("StatelessServer", stateless_http=True)
|
# mcp = FastMCP("StatelessServer", stateless_http=True)
|
||||||
|
|
||||||
# Stateless server (no session persistence, no sse stream with supported client)
|
# Stateless server (no session persistence, no sse stream with supported client)
|
||||||
mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
|
# mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Add a simple tool to demonstrate the server
|
||||||
|
@mcp.tool()
|
||||||
|
def greet(name: str = "World") -> str:
|
||||||
|
"""Greet someone by name."""
|
||||||
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
|
||||||
# Run server with streamable_http transport
|
# Run server with streamable_http transport
|
||||||
|
if __name__ == "__main__":
|
||||||
mcp.run(transport="streamable-http")
|
mcp.run(transport="streamable-http")
|
||||||
```
|
```
|
||||||
|
|
||||||
You can mount multiple FastMCP servers in a FastAPI application:
|
_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
|
You can mount multiple FastMCP servers in a Starlette application:
|
||||||
|
|
||||||
|
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
|
||||||
```python
|
```python
|
||||||
# echo.py
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
|
||||||
|
"""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.routing import Mount
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
mcp = FastMCP(name="EchoServer", stateless_http=True)
|
# Create the Echo server
|
||||||
|
echo_mcp = FastMCP(name="EchoServer", stateless_http=True)
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@echo_mcp.tool()
|
||||||
def echo(message: str) -> str:
|
def echo(message: str) -> str:
|
||||||
"""A simple echo tool"""
|
"""A simple echo tool"""
|
||||||
return f"Echo: {message}"
|
return f"Echo: {message}"
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
# math.py
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
|
||||||
|
|
||||||
mcp = FastMCP(name="MathServer", stateless_http=True)
|
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
# Create the Math server
|
||||||
|
math_mcp = FastMCP(name="MathServer", stateless_http=True)
|
||||||
|
|
||||||
|
|
||||||
|
@math_mcp.tool()
|
||||||
def add_two(n: int) -> int:
|
def add_two(n: int) -> int:
|
||||||
"""Tool to add two to the input"""
|
"""Tool to add two to the input"""
|
||||||
return n + 2
|
return n + 2
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
# main.py
|
|
||||||
import contextlib
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from mcp.echo import echo
|
|
||||||
from mcp.math import math
|
|
||||||
|
|
||||||
|
|
||||||
# Create a combined lifespan to manage both session managers
|
# Create a combined lifespan to manage both session managers
|
||||||
@contextlib.asynccontextmanager
|
@contextlib.asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: Starlette):
|
||||||
async with contextlib.AsyncExitStack() as stack:
|
async with contextlib.AsyncExitStack() as stack:
|
||||||
await stack.enter_async_context(echo.mcp.session_manager.run())
|
await stack.enter_async_context(echo_mcp.session_manager.run())
|
||||||
await stack.enter_async_context(math.mcp.session_manager.run())
|
await stack.enter_async_context(math_mcp.session_manager.run())
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
app = FastAPI(lifespan=lifespan)
|
# Create the Starlette app and mount the MCP servers
|
||||||
app.mount("/echo", echo.mcp.streamable_http_app())
|
app = Starlette(
|
||||||
app.mount("/math", math.mcp.streamable_http_app())
|
routes=[
|
||||||
|
Mount("/echo", echo_mcp.streamable_http_app()),
|
||||||
|
Mount("/math", math_mcp.streamable_http_app()),
|
||||||
|
],
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
For low level server with Streamable HTTP implementations, see:
|
For low level server with Streamable HTTP implementations, see:
|
||||||
|
|
||||||
- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/)
|
- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/)
|
||||||
|
|
@ -945,26 +970,6 @@ The streamable HTTP transport supports:
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
#### Streamable HTTP servers
|
|
||||||
|
|
||||||
The following example shows how to use `streamable_http_app()`, a method that returns a `Starlette` application object.
|
|
||||||
You can then append additional routes to that application as needed.
|
|
||||||
|
|
||||||
```python
|
|
||||||
mcp = FastMCP("My App")
|
|
||||||
|
|
||||||
app = mcp.streamable_http_app()
|
|
||||||
# Additional non-MCP routes can be added like so:
|
|
||||||
# from starlette.routing import Route
|
|
||||||
# app.router.routes.append(Route("/", endpoint=other_route_function))
|
|
||||||
```
|
|
||||||
|
|
||||||
To customize the route from the default of "/mcp", either specify the `streamable_http_path` option for the `FastMCP` constructor,
|
|
||||||
or set `FASTMCP_STREAMABLE_HTTP_PATH` environment variable.
|
|
||||||
|
|
||||||
Note that in Starlette and FastAPI (which is based on Starlette), the "/mcp" route will redirect to "/mcp/",
|
|
||||||
so you may need to use "/mcp/" when pointing MCP clients at your servers.
|
|
||||||
|
|
||||||
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
|
For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes).
|
||||||
|
|
||||||
#### SSE servers
|
#### SSE servers
|
||||||
|
|
@ -1336,9 +1341,7 @@ The SDK provides a high-level client interface for connecting to MCP servers usi
|
||||||
|
|
||||||
<!-- snippet-source examples/snippets/clients/stdio_client.py -->
|
<!-- snippet-source examples/snippets/clients/stdio_client.py -->
|
||||||
```python
|
```python
|
||||||
"""MCP client example using stdio transport.
|
"""
|
||||||
|
|
||||||
This is a documentation example showing how to write an MCP client.
|
|
||||||
cd to the `examples/snippets/clients` directory and run:
|
cd to the `examples/snippets/clients` directory and run:
|
||||||
uv run client
|
uv run client
|
||||||
"""
|
"""
|
||||||
|
|
@ -1428,14 +1431,22 @@ _Full example: [examples/snippets/clients/stdio_client.py](https://github.com/mo
|
||||||
|
|
||||||
Clients can also connect using [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http):
|
Clients can also connect using [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http):
|
||||||
|
|
||||||
|
<!-- snippet-source examples/snippets/clients/streamable_basic.py -->
|
||||||
```python
|
```python
|
||||||
from mcp.client.streamable_http import streamablehttp_client
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uv run examples/snippets/clients/streamable_basic.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from mcp import ClientSession
|
from mcp import ClientSession
|
||||||
|
from mcp.client.streamable_http import streamablehttp_client
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
# Connect to a streamable HTTP server
|
# Connect to a streamable HTTP server
|
||||||
async with streamablehttp_client("example/mcp") as (
|
async with streamablehttp_client("http://localhost:8000/mcp") as (
|
||||||
read_stream,
|
read_stream,
|
||||||
write_stream,
|
write_stream,
|
||||||
_,
|
_,
|
||||||
|
|
@ -1444,21 +1455,25 @@ async def main():
|
||||||
async with ClientSession(read_stream, write_stream) as session:
|
async with ClientSession(read_stream, write_stream) as session:
|
||||||
# Initialize the connection
|
# Initialize the connection
|
||||||
await session.initialize()
|
await session.initialize()
|
||||||
# Call a tool
|
# List available tools
|
||||||
tool_result = await session.call_tool("echo", {"message": "hello"})
|
tools = await session.list_tools()
|
||||||
|
print(f"Available tools: {[tool.name for tool in tools.tools]}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Full example: [examples/snippets/clients/streamable_basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/streamable_basic.py)_
|
||||||
|
<!-- /snippet-source -->
|
||||||
|
|
||||||
### Client Display Utilities
|
### Client Display Utilities
|
||||||
|
|
||||||
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
|
When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts:
|
||||||
|
|
||||||
<!-- snippet-source examples/snippets/clients/display_utilities.py -->
|
<!-- snippet-source examples/snippets/clients/display_utilities.py -->
|
||||||
```python
|
```python
|
||||||
"""Client display utilities example.
|
"""
|
||||||
|
|
||||||
This example shows how to use the SDK's display utilities to show
|
|
||||||
human-readable names for tools, resources, and prompts.
|
|
||||||
|
|
||||||
cd to the `examples/snippets` directory and run:
|
cd to the `examples/snippets` directory and run:
|
||||||
uv run display-utilities-client
|
uv run display-utilities-client
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
"""MCP client example showing completion usage.
|
"""
|
||||||
|
|
||||||
This example demonstrates how to use the completion feature in MCP clients.
|
|
||||||
cd to the `examples/snippets` directory and run:
|
cd to the `examples/snippets` directory and run:
|
||||||
uv run completion-client
|
uv run completion-client
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
"""Client display utilities example.
|
"""
|
||||||
|
|
||||||
This example shows how to use the SDK's display utilities to show
|
|
||||||
human-readable names for tools, resources, and prompts.
|
|
||||||
|
|
||||||
cd to the `examples/snippets` directory and run:
|
cd to the `examples/snippets` directory and run:
|
||||||
uv run display-utilities-client
|
uv run display-utilities-client
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
"""MCP client example using stdio transport.
|
"""
|
||||||
|
|
||||||
This is a documentation example showing how to write an MCP client.
|
|
||||||
cd to the `examples/snippets/clients` directory and run:
|
cd to the `examples/snippets/clients` directory and run:
|
||||||
uv run client
|
uv run client
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
29
examples/snippets/clients/streamable_basic.py
Normal file
29
examples/snippets/clients/streamable_basic.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uv run examples/snippets/clients/streamable_basic.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from mcp import ClientSession
|
||||||
|
from mcp.client.streamable_http import streamablehttp_client
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# Connect to a streamable HTTP server
|
||||||
|
async with streamablehttp_client("http://localhost:8000/mcp") as (
|
||||||
|
read_stream,
|
||||||
|
write_stream,
|
||||||
|
_,
|
||||||
|
):
|
||||||
|
# Create a session using the client streams
|
||||||
|
async with ClientSession(read_stream, write_stream) as session:
|
||||||
|
# Initialize the connection
|
||||||
|
await session.initialize()
|
||||||
|
# List available tools
|
||||||
|
tools = await session.list_tools()
|
||||||
|
print(f"Available tools: {[tool.name for tool in tools.tools]}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
28
examples/snippets/servers/streamable_config.py
Normal file
28
examples/snippets/servers/streamable_config.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uv run examples/snippets/servers/streamable_config.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
# Stateful server (maintains session state)
|
||||||
|
mcp = FastMCP("StatefulServer")
|
||||||
|
|
||||||
|
# Other configuration options:
|
||||||
|
# Stateless server (no session persistence)
|
||||||
|
# mcp = FastMCP("StatelessServer", stateless_http=True)
|
||||||
|
|
||||||
|
# Stateless server (no session persistence, no sse stream with supported client)
|
||||||
|
# mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Add a simple tool to demonstrate the server
|
||||||
|
@mcp.tool()
|
||||||
|
def greet(name: str = "World") -> str:
|
||||||
|
"""Greet someone by name."""
|
||||||
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
|
||||||
|
# Run server with streamable_http transport
|
||||||
|
if __name__ == "__main__":
|
||||||
|
mcp.run(transport="streamable-http")
|
||||||
49
examples/snippets/servers/streamable_starlette_mount.py
Normal file
49
examples/snippets/servers/streamable_starlette_mount.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""
|
||||||
|
Run from the repository root:
|
||||||
|
uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload
|
||||||
|
"""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.routing import Mount
|
||||||
|
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
# Create the Echo server
|
||||||
|
echo_mcp = FastMCP(name="EchoServer", stateless_http=True)
|
||||||
|
|
||||||
|
|
||||||
|
@echo_mcp.tool()
|
||||||
|
def echo(message: str) -> str:
|
||||||
|
"""A simple echo tool"""
|
||||||
|
return f"Echo: {message}"
|
||||||
|
|
||||||
|
|
||||||
|
# Create the Math server
|
||||||
|
math_mcp = FastMCP(name="MathServer", stateless_http=True)
|
||||||
|
|
||||||
|
|
||||||
|
@math_mcp.tool()
|
||||||
|
def add_two(n: int) -> int:
|
||||||
|
"""Tool to add two to the input"""
|
||||||
|
return n + 2
|
||||||
|
|
||||||
|
|
||||||
|
# Create a combined lifespan to manage both session managers
|
||||||
|
@contextlib.asynccontextmanager
|
||||||
|
async def lifespan(app: Starlette):
|
||||||
|
async with contextlib.AsyncExitStack() as stack:
|
||||||
|
await stack.enter_async_context(echo_mcp.session_manager.run())
|
||||||
|
await stack.enter_async_context(math_mcp.session_manager.run())
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
# Create the Starlette app and mount the MCP servers
|
||||||
|
app = Starlette(
|
||||||
|
routes=[
|
||||||
|
Mount("/echo", echo_mcp.streamable_http_app()),
|
||||||
|
Mount("/math", math_mcp.streamable_http_app()),
|
||||||
|
],
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue