From b5327f4d97be6ca8c80f3ed75c8956180d66dbd3 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Mon, 20 Oct 2025 11:27:15 -0700 Subject: [PATCH 1/3] docs: Update examples to use stateless HTTP with JSON responses Update README and example code to consistently recommend and demonstrate stateless HTTP with JSON responses (stateless_http=True, json_response=True) as the recommended pattern for production deployments. Changes: - Update quickstart example to use stateless HTTP + JSON and make it executable - Update all streamable HTTP mounting examples with recommended config - Update OAuth server example with recommended config - Reorder streamable_config.py to show recommended option first - Change quickstart integration instructions to use Claude Code with HTTP - Clarify that stateless HTTP + JSON is optimal for scalability This encourages users away from stdio/SSE/stateful HTTP patterns that have extra complexity and makes servers less reliable for most use cases. --- README.md | 48 ++++++++++++------- .../snippets/servers/fastmcp_quickstart.py | 11 +++-- examples/snippets/servers/oauth_server.py | 2 + .../snippets/servers/streamable_config.py | 10 ++-- .../servers/streamable_http_basic_mounting.py | 2 +- .../servers/streamable_http_host_mounting.py | 2 +- .../streamable_http_multiple_servers.py | 4 +- .../servers/streamable_http_path_config.py | 7 ++- .../servers/streamable_starlette_mount.py | 4 +- 9 files changed, 57 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index a0daf5c6d..1edecc662 100644 --- a/README.md +++ b/README.md @@ -132,14 +132,14 @@ Let's create a simple MCP server that exposes a calculator tool and some data: """ FastMCP quickstart example. -cd to the `examples/snippets/clients` directory and run: - uv run server fastmcp_quickstart stdio +Run from the repository root: + uv run examples/snippets/servers/fastmcp_quickstart.py """ from mcp.server.fastmcp import FastMCP # Create an MCP server -mcp = FastMCP("Demo") +mcp = FastMCP("Demo", stateless_http=True, json_response=True) # Add an addition tool @@ -167,15 +167,20 @@ def greet_user(name: str, style: str = "friendly") -> str: } return f"{styles.get(style, styles['friendly'])} for someone named {name}." + + +# Run with streamable HTTP transport +if __name__ == "__main__": + mcp.run(transport="streamable-http") ``` _Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_ -You can install this server in [Claude Desktop](https://claude.ai/download) and interact with it right away by running: +You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away by running: ```bash -uv run mcp install server.py +claude mcp add --transport http my-server http://localhost:8000/mcp ``` Alternatively, you can test it with the MCP Inspector: @@ -888,6 +893,8 @@ class SimpleTokenVerifier(TokenVerifier): # Create FastMCP instance as a Resource Server mcp = FastMCP( "Weather Service", + stateless_http=True, + json_response=True, # Token verifier for authentication token_verifier=SimpleTokenVerifier(), # Auth settings for RFC 9728 Protected Resource Metadata @@ -1103,7 +1110,7 @@ Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMC ### Streamable HTTP Transport -> **Note**: Streamable HTTP transport is superseding SSE transport for production deployments. +> **Note**: Streamable HTTP transport is the recommended transport for production deployments. Use `stateless_http=True` and `json_response=True` for optimal scalability. ```python @@ -1114,15 +1121,15 @@ Run from the repository root: from mcp.server.fastmcp import FastMCP -# Stateful server (maintains session state) -mcp = FastMCP("StatefulServer") +# Stateless server with JSON responses (recommended) +mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True) # Other configuration options: -# Stateless server (no session persistence) +# Stateless server with SSE streaming responses # 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) +# Stateful server with session persistence +# mcp = FastMCP("StatefulServer") # Add a simple tool to demonstrate the server @@ -1157,7 +1164,7 @@ 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 = FastMCP(name="EchoServer", stateless_http=True, json_response=True) @echo_mcp.tool() @@ -1167,7 +1174,7 @@ def echo(message: str) -> str: # Create the Math server -math_mcp = FastMCP(name="MathServer", stateless_http=True) +math_mcp = FastMCP(name="MathServer", stateless_http=True, json_response=True) @math_mcp.tool() @@ -1268,7 +1275,7 @@ from starlette.routing import Mount from mcp.server.fastmcp import FastMCP # Create MCP server -mcp = FastMCP("My App") +mcp = FastMCP("My App", stateless_http=True, json_response=True) @mcp.tool() @@ -1305,7 +1312,7 @@ from starlette.routing import Host from mcp.server.fastmcp import FastMCP # Create MCP server -mcp = FastMCP("MCP Host App") +mcp = FastMCP("MCP Host App", stateless_http=True, json_response=True) @mcp.tool() @@ -1342,8 +1349,8 @@ from starlette.routing import Mount from mcp.server.fastmcp import FastMCP # Create multiple MCP servers -api_mcp = FastMCP("API Server") -chat_mcp = FastMCP("Chat Server") +api_mcp = FastMCP("API Server", stateless_http=True, json_response=True) +chat_mcp = FastMCP("Chat Server", stateless_http=True, json_response=True) @api_mcp.tool() @@ -1393,7 +1400,12 @@ from mcp.server.fastmcp import FastMCP # Configure streamable_http_path during initialization # This server will mount at the root of wherever it's mounted -mcp_at_root = FastMCP("My Server", streamable_http_path="/") +mcp_at_root = FastMCP( + "My Server", + stateless_http=True, + json_response=True, + streamable_http_path="/", +) @mcp_at_root.tool() diff --git a/examples/snippets/servers/fastmcp_quickstart.py b/examples/snippets/servers/fastmcp_quickstart.py index d7aef8c61..3af39c22a 100644 --- a/examples/snippets/servers/fastmcp_quickstart.py +++ b/examples/snippets/servers/fastmcp_quickstart.py @@ -1,14 +1,14 @@ """ FastMCP quickstart example. -cd to the `examples/snippets/clients` directory and run: - uv run server fastmcp_quickstart stdio +Run from the repository root: + uv run examples/snippets/servers/fastmcp_quickstart.py """ from mcp.server.fastmcp import FastMCP # Create an MCP server -mcp = FastMCP("Demo") +mcp = FastMCP("Demo", stateless_http=True, json_response=True) # Add an addition tool @@ -36,3 +36,8 @@ def greet_user(name: str, style: str = "friendly") -> str: } return f"{styles.get(style, styles['friendly'])} for someone named {name}." + + +# Run with streamable HTTP transport +if __name__ == "__main__": + mcp.run(transport="streamable-http") diff --git a/examples/snippets/servers/oauth_server.py b/examples/snippets/servers/oauth_server.py index bd317e1ae..e31a79bd2 100644 --- a/examples/snippets/servers/oauth_server.py +++ b/examples/snippets/servers/oauth_server.py @@ -20,6 +20,8 @@ async def verify_token(self, token: str) -> AccessToken | None: # Create FastMCP instance as a Resource Server mcp = FastMCP( "Weather Service", + stateless_http=True, + json_response=True, # Token verifier for authentication token_verifier=SimpleTokenVerifier(), # Auth settings for RFC 9728 Protected Resource Metadata diff --git a/examples/snippets/servers/streamable_config.py b/examples/snippets/servers/streamable_config.py index e265f6381..d351a45d8 100644 --- a/examples/snippets/servers/streamable_config.py +++ b/examples/snippets/servers/streamable_config.py @@ -5,15 +5,15 @@ from mcp.server.fastmcp import FastMCP -# Stateful server (maintains session state) -mcp = FastMCP("StatefulServer") +# Stateless server with JSON responses (recommended) +mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True) # Other configuration options: -# Stateless server (no session persistence) +# Stateless server with SSE streaming responses # 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) +# Stateful server with session persistence +# mcp = FastMCP("StatefulServer") # Add a simple tool to demonstrate the server diff --git a/examples/snippets/servers/streamable_http_basic_mounting.py b/examples/snippets/servers/streamable_http_basic_mounting.py index abcc0e572..e2c65ca40 100644 --- a/examples/snippets/servers/streamable_http_basic_mounting.py +++ b/examples/snippets/servers/streamable_http_basic_mounting.py @@ -11,7 +11,7 @@ from mcp.server.fastmcp import FastMCP # Create MCP server -mcp = FastMCP("My App") +mcp = FastMCP("My App", stateless_http=True, json_response=True) @mcp.tool() diff --git a/examples/snippets/servers/streamable_http_host_mounting.py b/examples/snippets/servers/streamable_http_host_mounting.py index d48558cc8..a02e3fba3 100644 --- a/examples/snippets/servers/streamable_http_host_mounting.py +++ b/examples/snippets/servers/streamable_http_host_mounting.py @@ -11,7 +11,7 @@ from mcp.server.fastmcp import FastMCP # Create MCP server -mcp = FastMCP("MCP Host App") +mcp = FastMCP("MCP Host App", stateless_http=True, json_response=True) @mcp.tool() diff --git a/examples/snippets/servers/streamable_http_multiple_servers.py b/examples/snippets/servers/streamable_http_multiple_servers.py index df347b7b3..2aeaa2214 100644 --- a/examples/snippets/servers/streamable_http_multiple_servers.py +++ b/examples/snippets/servers/streamable_http_multiple_servers.py @@ -11,8 +11,8 @@ from mcp.server.fastmcp import FastMCP # Create multiple MCP servers -api_mcp = FastMCP("API Server") -chat_mcp = FastMCP("Chat Server") +api_mcp = FastMCP("API Server", stateless_http=True, json_response=True) +chat_mcp = FastMCP("Chat Server", stateless_http=True, json_response=True) @api_mcp.tool() diff --git a/examples/snippets/servers/streamable_http_path_config.py b/examples/snippets/servers/streamable_http_path_config.py index 71228423e..48420f607 100644 --- a/examples/snippets/servers/streamable_http_path_config.py +++ b/examples/snippets/servers/streamable_http_path_config.py @@ -12,7 +12,12 @@ # Configure streamable_http_path during initialization # This server will mount at the root of wherever it's mounted -mcp_at_root = FastMCP("My Server", streamable_http_path="/") +mcp_at_root = FastMCP( + "My Server", + stateless_http=True, + json_response=True, + streamable_http_path="/", +) @mcp_at_root.tool() diff --git a/examples/snippets/servers/streamable_starlette_mount.py b/examples/snippets/servers/streamable_starlette_mount.py index 57d2d2ea5..b3a630b0f 100644 --- a/examples/snippets/servers/streamable_starlette_mount.py +++ b/examples/snippets/servers/streamable_starlette_mount.py @@ -11,7 +11,7 @@ from mcp.server.fastmcp import FastMCP # Create the Echo server -echo_mcp = FastMCP(name="EchoServer", stateless_http=True) +echo_mcp = FastMCP(name="EchoServer", stateless_http=True, json_response=True) @echo_mcp.tool() @@ -21,7 +21,7 @@ def echo(message: str) -> str: # Create the Math server -math_mcp = FastMCP(name="MathServer", stateless_http=True) +math_mcp = FastMCP(name="MathServer", stateless_http=True, json_response=True) @math_mcp.tool() From 2b4552fe65c54862b7ca8787086267f7f332b5c7 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Mon, 20 Oct 2025 11:29:32 -0700 Subject: [PATCH 2/3] docs: Update index.md example to use stateless HTTP with JSON --- docs/index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 139afca4a..c8ffe2a4f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,7 +17,7 @@ Here's a simple MCP server that exposes a tool, resource, and prompt: ```python title="server.py" from mcp.server.fastmcp import FastMCP -mcp = FastMCP("Test Server") +mcp = FastMCP("Test Server", stateless_http=True, json_response=True) @mcp.tool() @@ -36,6 +36,10 @@ def get_greeting(name: str) -> str: def greet_user(name: str, style: str = "friendly") -> str: """Generate a greeting prompt""" return f"Write a {style} greeting for someone named {name}." + + +if __name__ == "__main__": + mcp.run(transport="streamable-http") ``` Test it with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector): From cbfb9d8e978a6e383eb2dec11751326eb070c7e6 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Mon, 20 Oct 2025 11:42:51 -0700 Subject: [PATCH 3/3] docs: Update quickstart instructions for testing with inspector Change from 'uv run mcp dev' to the simpler two-step approach: 1. Run server with 'uv run --with mcp server.py' 2. Open inspector with 'npx -y @modelcontextprotocol/inspector' and connect manually This avoids the complexity of mcp dev trying to manage stdio vs HTTP transport and gives users more control over the connection. --- README.md | 14 +++++++++++--- docs/index.md | 10 ++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1edecc662..304bea78c 100644 --- a/README.md +++ b/README.md @@ -177,18 +177,26 @@ if __name__ == "__main__": _Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_ -You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away by running: +You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server: + +```bash +uv run --with mcp examples/snippets/servers/fastmcp_quickstart.py +``` + +Then add it to Claude Code: ```bash claude mcp add --transport http my-server http://localhost:8000/mcp ``` -Alternatively, you can test it with the MCP Inspector: +Alternatively, you can test it with the MCP Inspector. Start the server as above, then in a separate terminal: ```bash -uv run mcp dev server.py +npx -y @modelcontextprotocol/inspector ``` +In the inspector UI, connect to `http://localhost:8000/mcp`. + ## What is MCP? The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can: diff --git a/docs/index.md b/docs/index.md index c8ffe2a4f..bc4bb048b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -42,10 +42,16 @@ if __name__ == "__main__": mcp.run(transport="streamable-http") ``` -Test it with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector): +Run the server: ```bash -uv run mcp dev server.py +uv run --with mcp server.py +``` + +Then open the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) and connect to `http://localhost:8000/mcp`: + +```bash +npx -y @modelcontextprotocol/inspector ``` ## Getting Started