跳转至

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 配置:

{
  "mcpServers": {
    "remote-sse": {
      "url": "http://my-server.com:8000/sse"
    }
  }
}

优点

  • 支持远程 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

客户端连接

{
  "mcpServers": {
    "remote-http": {
      "url": "http://my-server.com:8000/mcp"
    }
  }
}

优点

  • 协议简单:标准 HTTP,所有工具都支持
  • 代理友好:能放在 Nginx、CDN 后面
  • 生产就绪:支持负载均衡、横向扩展
  • 认证标准:可以用 OAuth2、JWT 等通用方案

缺点

  • 不支持双向流式(Tool 报告进度场景需要降级处理)

新项目首选 Streamable HTTP,特别是云端部署。

5. 部署对比

本地工具(stdio)

if __name__ == "__main__":
    mcp.run()

打包成命令行工具,发布到 PyPI,用户:

pip install your-mcp-server

然后在 Claude Desktop 配置:

{"command": "your-mcp-server"}

云端服务(Streamable HTTP)

if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

部署到 Docker / Kubernetes:

FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install "mcp[cli]"
EXPOSE 8000
CMD ["python", "server.py"]
docker build -t my-mcp .
docker run -p 8000:8000 -e API_KEY=xxx my-mcp

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)
python server.py stdio              # 本地用
python server.py streamable-http    # 远程部署

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

评论