MCP 为什么不用 HTTP 或 gRPC?
作者:程序员马丁
note
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
问题的本质:MCP 要解决什么问题?
在讨论技术选型之前,我们需要先明确 MCP(Model Context Protocol)要解决的核心问题。
MCP 的目标是让大模型能够以统一、标准、可互操作的方式调用外部工具能力。这意味着:
- 不同语言实现的 MCP Server(Python、Java、Node.js)都能被同一个 MCP Client 调用
- 不同厂商的大模型(OpenAI、Anthropic、本地模型)都能用相同方式调用工具
- 工具的调用方式应该是明确、可预测的,而不是各自为政
要实现这个目标,MCP 需要的不是如何传输数据,而是如何表达一次调用。
HTTP、gRPC 和 JSON-RPC 2.0 的定位差异
1. HTTP:传输协议,不是调用协议
HTTP 是一个传输层协议,它定义了:
- 如何建立连接(TCP/TLS)
- 如何发送请求(GET、POST、PUT、DELETE)
- 如何返回响应(状态码、Header、Body)
但 HTTP 不定义:
- 方法名怎么表示?(是放在 URL 路径?还是 Body 里?)
- 参数怎么传递?(Query String?JSON Body?Form Data?)
- 错误怎么表达?(HTTP 状态码?还是 Body 里的错误对象?)
- 通知消息(不需要响应的调用)怎么处理?
这导致基于 HTTP 的 API 设计千差万别:
- RESTful API:
POST /users、GET /users/123 - RPC-style API:
POST /api+{"method": "getUser", "params": {...}} - GraphQL:
POST /graphql+ Query DSL
每种风格都有自己的约定,缺乏统一标准。
2. gRPC:强类型 RPC 框架,但过于重量级
gRPC 是一个完整的 RPC 框架,它提供了:
- 基于 Protocol Buffers 的强类型接口定义
- HTTP/2 传输层
- 流式调用支持
- 多语言代码生成
gRPC 的优势在于性能和类型安全,但它也带来了额外的复杂度:
- 需要预先定义 .proto 文件:每个工具都要写 Protocol Buffers 定义,增加了开发成本
- 强依赖代码生成:客户端和服务端都需要生成代码,动态调用不方便
- 二进制协议不易调试:无法直接用 curl 或浏览器测试,必须用专门工具
- HTTP/2 依赖:部分环境(如浏览器、某些代理)对 HTTP/2 支持不完善
对于 MCP 这种需要轻量、灵活、易于调试的场景,gRPC 显得过于重量级。
3. JSON-RPC 2.0:协议层标准,专注消息格式
JSON-RPC 2.0 的定位与 HTTP、gRPC 都不同,它是一个消息格式规范,只定义:
- 一次调用的请求结构:
{"jsonrpc": "2.0", "method": "...", "params": {...}, "id": 1} - 成功响应的结构:
{"jsonrpc": "2.0", "result": {...}, "id": 1} - 错误响应的结构:
{"jsonrpc": "2.0", "error": {...}, "id": 1} - 通知消息的结构:
{"jsonrpc": "2.0", "method": "...", "params": {...}}(无id)
它不绑定传输层,可以跑在:
- HTTP 之上(最常见)
- WebSocket 之上(实时通信)
- stdio 之上(进程间通信)
- 任何能传输 JSON 的通道
MCP 选择 JSON-RPC 2.0 的核心原因
1. 统一的消息格式
JSON-RPC 2.0 提供了一套明确、标准、无歧义的消息结构:
// 请求
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {"city": "Beijing"}
},
"id": 1
}
// 成功响应
{
"jsonrpc": "2.0",
"result": {
"content": [{"type": "text", "text": "北京今天晴,25°C"}]
},
"id": 1
}
// 错误响应
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params",
"data": "city is required"
},
"id": 1
}
无论是 Python 实现的 MCP Server,还是 Java 实现的 MCP Client,都能按照完全相同的方式解析和构造消息。