| title | Transport Modes |
|---|---|
| description | Learn about stdio and HTTP transport modes for MCP servers |
import { Callout } from "nextra/components";
MCP servers can communicate with clients through different transport mechanisms. Each transport is optimized for specific use cases and client types.
The stdio transport is the default transport for MCP servers. It is used by Claude Desktop and similar clients to run tools locally. Learn more about the different [server types](/home/compare-server-types).The stdio (standard input/output) transport is used for direct client connections.
- Communicates via standard input/output streams
- Logs go to stderr to avoid interfering with protocol messages
- Ideal for desktop applications and command-line tools
- Used by Claude Desktop and similar clients
Recommended: Using Arcade CLI
# Run with stdio transport
uv run server.py stdioAlternative: Direct Python
# Run your server directly
uv run server.py stdio
# Or with python
app.run(transport="stdio")For Claude Desktop, use the arcade configure command:
arcade configure claude --host localOr manually edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"my-tools": {
"command": "arcade",
"args": ["mcp", "stdio"],
"cwd": "/path/to/your/tools"
}
}
}The HTTP transport provides REST/SSE endpoints for web-based clients.
- RESTful API with Server-Sent Events (SSE) for streaming
- Supports hot reload for development
- Includes health checks and API documentation
- Can be deployed behind reverse proxies
- Suitable for web applications and services
Recommended: Using Arcade CLI
# Run with HTTP transport (default)
uv run server.py
uv run server.py httpAlternative: Direct Python
# Run your server directly
uv run server.py
# Or with python
app.run(transport="http", host="0.0.0.0", port=8080)When running in HTTP mode, the server provides:
| Endpoint | Method | Description |
|---|---|---|
/worker/health |
GET | Health check (returns 200 OK) |
/mcp |
GET | SSE stream for server-initiated messages |
/mcp |
POST | Send JSON-RPC message |
/mcp |
DELETE | Terminate session (when using session IDs) |
/docs |
GET | Swagger UI documentation (debug mode) |
/redoc |
GET | ReDoc documentation (debug mode) |
With Arcade CLI:
# Enable hot reload and debug mode
app.run(host="127.0.0.1", port=8000, reload=True)
# This enables:
# - Automatic restart on code changes
# - Detailed error messages
# - API documentation endpoints
# - Verbose logging- Integrating with desktop applications (Claude Desktop, VS Code)
- Building command-line tools
- You need simple, direct communication
- Running in environments without network access
- Building web applications
- Deploying to cloud environments
- You need to support multiple concurrent clients
- Integrating with existing web services
- You want API documentation and testing tools
Both transports respect common environment variables:
# Server identification
MCP_SERVER_NAME="My MCP Server"
MCP_SERVER_VERSION="1.0.0"
# Logging
MCP_DEBUG=true
MCP_LOG_LEVEL=DEBUG
# HTTP-specific
MCP_HTTP_HOST=0.0.0.0
MCP_HTTP_PORT=8080When using MCPApp:
from arcade_mcp_server import MCPApp
app = MCPApp(
name="my-server",
version="1.0.0",
log_level="DEBUG"
)
# Run with specific transport
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "stdio":
app.run(transport="stdio")
else:
app.run(transport="http", host="0.0.0.0", port=8080)- Inherits security context of the parent process
- No network exposure
- Suitable for trusted environments
- Exposes network endpoints
- Should use authentication in production
- Consider using HTTPS with reverse proxy
- Implement rate limiting for public deployments
Add custom middleware to HTTP transports:
from arcade_mcp_server import MCPApp
app = MCPApp(name="my-server")
# Add custom middleware
@app.middleware("http")
async def add_custom_headers(request, call_next):
response = await call_next(request)
response.headers["X-Custom-Header"] = "value"
return responseListen to transport lifecycle events:
@app.on_event("startup")
async def startup_handler():
print("Server starting up...")
@app.on_event("shutdown")
async def shutdown_handler():
print("Server shutting down...")