MCP传输协议
MCP 协议本身和传输方式无关,但实际部署时怎么传输决定了 Server 能在哪里运行、如何被调用。本篇讲清楚三种传输方式及其适用场景。
1. 三种传输方式概览
| 传输方式 | 物理形式 | 主要场景 | 推出时间 |
|---|---|---|---|
| stdio | 子进程 + 标准输入输出 | 本地工具、桌面应用 | 最早 |
| SSE | HTTP + Server-Sent Events | 远程 Server、Web 应用 | 早期 |
| Streamable HTTP | 纯 HTTP(请求/响应) | 云端部署、生产环境 | 2025 年 |
2. stdio:本地子进程
最常用的传输方式,Server 是 Host 启动的本地子进程,通过标准输入输出通信。
┌──────────────────┐
│ Host (Claude │
│ Desktop) │
│ │
│ ┌──────────┐ │ stdin (JSON-RPC)
│ │ Client │────┼──────────────┐
│ └──────────┘ │ ↓
│ │ stdout ┌─────────────┐
│ ←──────────┼─────────────│ MCP Server │
│ │ │ (子进程) │
└──────────────────┘ └─────────────┘
启动配置
Claude Desktop 的 claude_desktop_config.json:
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {
"API_KEY": "secret-key"
}
}
}
}
command + args 启动子进程,env 注入环境变量。
Python Server 代码
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("local-tools")
@mcp.tool()
def hello(name: str) -> str:
return f"你好,{name}"
if __name__ == "__main__":
mcp.run() # 默认就是 stdio
# 等价于:mcp.run(transport="stdio")
优点
- 零网络配置:不需要端口、HTTPS、防火墙
- 进程隔离:每次启动一个独立进程,崩溃不影响 Host
- 本地优先:数据不出设备
- 环境变量隔离:每个 Server 单独配 env,秘钥不互通
缺点
- 只能本地:跨机器、跨用户共享需要其他方式
- 进程开销:每个 Server 一个进程,多了占内存
- 冷启动:启动需要 100ms~几秒
不能用 print
stdio 模式下,stdout 是协议通道,任何 print 都会破坏协议。日志必须输出到 stderr:
import sys
import logging
logging.basicConfig(
level=logging.INFO,
stream=sys.stderr,
format="%(asctime)s [%(levelname)s] %(message)s",
)
3. SSE:基于 HTTP 长连接
SSE(Server-Sent Events)是 HTML5 的服务器推送技术。MCP over SSE 让 Server 作为独立的 HTTP 服务运行:
┌──────────┐ HTTP POST ┌─────────────┐
│ Client │───── /messages ───→│ │
│ │ │ MCP Server │
│ │←──── /sse ─────────│ (HTTP 服务) │
└──────────┘ SSE 长连接 └─────────────┘
两个端点:
POST /messages:客户端发送请求GET /sse:服务端通过 SSE 推送响应和通知
Python Server(SSE)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("sse-demo")
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
mcp.run(transport="sse") # 启用 SSE 传输
默认监听 0.0.0.0:8000,启动后访问 http://localhost:8000/sse 就能看到 SSE 流。
客户端连接
Claude Desktop 配置:
优点
- 支持远程 Server
- 一个 Server 可以服务多个客户端
- 可以部署在云上
缺点
- 协议复杂:需要维护 SSE 长连接、断线重连、超时处理
- 代理不友好:很多反向代理对 SSE 支持有限
- 被新协议替代:MCP 官方 2025 年起逐步迁移到 Streamable HTTP
新项目不推荐用 SSE,了解即可。
4. Streamable HTTP:现代标准
2025 年 MCP 推出的新传输方式,基于纯 HTTP,没有 SSE 的复杂性。
┌──────────┐ HTTP POST ┌─────────────┐
│ Client │──── /mcp ────────→│ MCP Server │
│ │←─── 响应 ──────────│ │
└──────────┘ └─────────────┘
只用一个端点 POST /mcp,请求-响应模式。
Python Server(Streamable HTTP)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("http-demo")
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
mcp.run(transport="streamable-http")
默认监听 127.0.0.1:8000/mcp。
客户端连接
优点
- 协议简单:标准 HTTP,所有工具都支持
- 代理友好:能放在 Nginx、CDN 后面
- 生产就绪:支持负载均衡、横向扩展
- 认证标准:可以用 OAuth2、JWT 等通用方案
缺点
- 不支持双向流式(Tool 报告进度场景需要降级处理)
新项目首选 Streamable HTTP,特别是云端部署。
5. 部署对比
本地工具(stdio)
打包成命令行工具,发布到 PyPI,用户:
然后在 Claude Desktop 配置:
云端服务(Streamable HTTP)
部署到 Docker / Kubernetes:
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install "mcp[cli]"
EXPOSE 8000
CMD ["python", "server.py"]
6. 远程 Server 的认证
stdio 没有认证问题(本地进程),但远程 Server 需要保护:
方式 1:HTTP Header
from mcp.server.fastmcp import FastMCP
from starlette.middleware.base import BaseHTTPMiddleware
mcp = FastMCP("secure-server")
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
token = request.headers.get("Authorization")
if token != "Bearer my-secret-token":
return JSONResponse({"error": "Unauthorized"}, status_code=401)
return await call_next(request)
# 自定义 starlette app
app = mcp.streamable_http_app()
app.add_middleware(AuthMiddleware)
客户端配置带 token:
{
"mcpServers": {
"secure": {
"url": "https://my-server.com/mcp",
"headers": {
"Authorization": "Bearer my-secret-token"
}
}
}
}
方式 2:OAuth2
MCP 规范支持 OAuth 2.1 标准流程,复杂场景(多用户、企业 SaaS)使用。具体配置见 MCP 官方文档。
7. 多传输支持
同一个 Server 可以支持多种传输,启动时切换:
import sys
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("multi-transport")
@mcp.tool()
def hello() -> str:
return "world"
if __name__ == "__main__":
transport = sys.argv[1] if len(sys.argv) > 1 else "stdio"
mcp.run(transport=transport)
8. 选型决策树
是不是本地工具,运行在用户机器上?
├── 是 → stdio
└── 否
├── 部署给单个用户用?
│ └── Streamable HTTP(简单认证)
└── 多租户、企业级?
└── Streamable HTTP + OAuth 2.1
9. 性能对比
简单的基准测试(请求 1000 次 add(1, 2)):
| 传输 | 延迟(P50) | 延迟(P99) | 吞吐 |
|---|---|---|---|
| stdio | < 1ms | ~ 5ms | ~ 5000 req/s |
| SSE | ~ 5ms | ~ 50ms | ~ 1000 req/s |
| Streamable HTTP | ~ 3ms | ~ 30ms | ~ 2000 req/s |
stdio 最快,因为没有网络开销。但实际场景中工具的执行时间通常远超传输开销,差距不明显。
10. 调试建议
stdio 调试:
- 用
mcp dev server.py启动 inspector - 日志输出到
~/Library/Logs/Claude/查看 - 不能 print,用 logging 到 stderr
HTTP 类调试:
- 用
curl直接调 endpoint 验证:
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
- 用 inspector 也支持 HTTP 模式
总结
- 三种传输方式:stdio(本地最佳)、SSE(已过时)、Streamable HTTP(远程首选)
- stdio 通过子进程标准输入输出通信,零网络配置,但只能本地
- Streamable HTTP 是 2025 年新标准,简单 HTTP,适合云端部署
- 远程 Server 必须做认证:简单场景用 HTTP Header,复杂场景用 OAuth 2.1
- 同一个 Server 可以支持多传输,通过启动参数切换
- 选型:本地工具用 stdio,云端部署用 Streamable HTTP,新项目不要选 SSE