chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# MCP stdio Server - Python Solution
|
||||
|
||||
> **⚠️ Important**: This solution has been updated to use the **stdio transport** as recommended by MCP Specification 2025-06-18. The original SSE transport has been deprecated.
|
||||
|
||||
## Overview
|
||||
|
||||
This Python solution demonstrates how to build an MCP server using the current stdio transport. The stdio transport is simpler, more secure, and provides better performance than the deprecated SSE approach.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.8 or later
|
||||
- You're recommended to install `uv` for package management, see [instructions](https://docs.astral.sh/uv/#highlights)
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### Step 1: Create a virtual environment
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
```
|
||||
|
||||
### Step 2: Activate the virtual environment
|
||||
|
||||
**Windows:**
|
||||
```bash
|
||||
venv\Scripts\activate
|
||||
```
|
||||
|
||||
**macOS/Linux:**
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
### Step 3: Install the dependencies
|
||||
|
||||
```bash
|
||||
pip install mcp
|
||||
```
|
||||
|
||||
## Running the Server
|
||||
|
||||
The stdio server runs differently than the old SSE server. Instead of starting a web server, it communicates through stdin/stdout:
|
||||
|
||||
```bash
|
||||
python server.py
|
||||
```
|
||||
|
||||
**Important**: The server will appear to hang - this is normal! It's waiting for JSON-RPC messages from stdin.
|
||||
|
||||
## Testing the Server
|
||||
|
||||
### Method 1: Using the MCP Inspector (Recommended)
|
||||
|
||||
```bash
|
||||
npx @modelcontextprotocol/inspector python server.py
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Launch your server as a subprocess
|
||||
2. Open a web interface for testing
|
||||
3. Allow you to test all server tools interactively
|
||||
|
||||
### Method 2: Direct JSON-RPC testing
|
||||
|
||||
You can also test by sending JSON-RPC messages directly:
|
||||
|
||||
1. Start the server: `python server.py`
|
||||
2. Send a JSON-RPC message (example):
|
||||
|
||||
```json
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}
|
||||
```
|
||||
|
||||
3. The server will respond with available tools
|
||||
|
||||
### Available Tools
|
||||
|
||||
The server provides these tools:
|
||||
|
||||
- **add(a, b)**: Add two numbers together
|
||||
- **multiply(a, b)**: Multiply two numbers together
|
||||
- **get_greeting(name)**: Generate a personalized greeting
|
||||
- **get_server_info()**: Get information about the server
|
||||
|
||||
### Testing with Claude Desktop
|
||||
|
||||
To use this server with Claude Desktop, add this configuration to your `claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"example-stdio-server": {
|
||||
"command": "python",
|
||||
"args": ["path/to/server.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Differences from SSE
|
||||
|
||||
**stdio transport (Current):**
|
||||
- ✅ Simpler setup - no web server needed
|
||||
- ✅ Better security - no HTTP endpoints
|
||||
- ✅ Subprocess-based communication
|
||||
- ✅ JSON-RPC over stdin/stdout
|
||||
- ✅ Better performance
|
||||
|
||||
**SSE transport (Deprecated):**
|
||||
- ❌ Required HTTP server setup
|
||||
- ❌ Needed web framework (Starlette/FastAPI)
|
||||
- ❌ More complex routing and session management
|
||||
- ❌ Additional security considerations
|
||||
- ❌ Now deprecated in MCP 2025-06-18
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
- Use `stderr` for logging (never `stdout`)
|
||||
- Test with the Inspector for visual debugging
|
||||
- Ensure all JSON messages are newline-delimited
|
||||
- Check that the server starts without errors
|
||||
|
||||
This solution follows the current MCP specification and demonstrates best practices for stdio transport implementation.
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MCP stdio server example - Updated for MCP Specification 2025-06-18
|
||||
|
||||
This server demonstrates the recommended stdio transport instead of the
|
||||
deprecated SSE transport. The stdio transport is simpler, more secure,
|
||||
and provides better performance.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from mcp.server import Server
|
||||
from mcp.server.stdio import stdio_server
|
||||
from mcp.types import Tool, TextContent
|
||||
|
||||
# Configure logging to stderr (never use stdout for logging in stdio servers)
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[logging.StreamHandler()]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Create the server
|
||||
server = Server("example-stdio-server")
|
||||
|
||||
# Define tools using list_tools and call_tool handlers
|
||||
@server.list_tools()
|
||||
async def list_tools() -> list[Tool]:
|
||||
"""List available tools"""
|
||||
return [
|
||||
Tool(
|
||||
name="add",
|
||||
description="Add two numbers together",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"a": {"type": "number", "description": "First number"},
|
||||
"b": {"type": "number", "description": "Second number"}
|
||||
},
|
||||
"required": ["a", "b"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="multiply",
|
||||
description="Multiply two numbers together",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"a": {"type": "number", "description": "First number"},
|
||||
"b": {"type": "number", "description": "Second number"}
|
||||
},
|
||||
"required": ["a", "b"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="get_greeting",
|
||||
description="Generate a personalized greeting",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "Name to greet"}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
),
|
||||
Tool(
|
||||
name="get_server_info",
|
||||
description="Get information about this MCP server",
|
||||
inputSchema={"type": "object", "properties": {}}
|
||||
)
|
||||
]
|
||||
|
||||
@server.call_tool()
|
||||
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
||||
"""Handle tool calls"""
|
||||
if name == "add":
|
||||
result = arguments["a"] + arguments["b"]
|
||||
logger.info(f"Adding {arguments['a']} + {arguments['b']} = {result}")
|
||||
return [TextContent(type="text", text=str(result))]
|
||||
|
||||
elif name == "multiply":
|
||||
result = arguments["a"] * arguments["b"]
|
||||
logger.info(f"Multiplying {arguments['a']} * {arguments['b']} = {result}")
|
||||
return [TextContent(type="text", text=str(result))]
|
||||
|
||||
elif name == "get_greeting":
|
||||
greeting = f"Hello, {arguments['name']}! Welcome to the MCP stdio server."
|
||||
logger.info(f"Generated greeting for {arguments['name']}")
|
||||
return [TextContent(type="text", text=greeting)]
|
||||
|
||||
elif name == "get_server_info":
|
||||
info = {
|
||||
"server_name": "example-stdio-server",
|
||||
"version": "1.0.0",
|
||||
"transport": "stdio",
|
||||
"capabilities": ["tools"],
|
||||
"description": "Example MCP server using stdio transport (MCP 2025-06-18 specification)"
|
||||
}
|
||||
return [TextContent(type="text", text=str(info))]
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unknown tool: {name}")
|
||||
|
||||
async def main():
|
||||
"""Main server function using stdio transport"""
|
||||
logger.info("Starting MCP stdio server...")
|
||||
|
||||
try:
|
||||
# Use stdio transport - this is the recommended approach
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
logger.info("Server connected via stdio transport")
|
||||
await server.run(
|
||||
read_stream,
|
||||
write_stream,
|
||||
server.create_initialization_options()
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Server error: {e}")
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user