01 · 协议地基:JSON-RPC 与消息形态
这一章讲 MCP 最底层的“话术”——所有交互都是 JSON-RPC 2.0 消息。搞懂请求/响应/通知三种形态、draft 新增的
resultType、错误码规则、以及每请求自带的_meta,后面所有机制都是在这之上搭的。
1.1 为什么是 JSON-RPC
MCP 不发明自己的线协议,直接用 JSON-RPC 2.0:一个极简、跨语言、无关传输的“远程调用”约定。客户端和服务器之间的每一条消息都必须符合 JSON-RPC(docs/specification/draft/basic/index.mdx:27)。
好处很实在:任何语言都有现成 JSON 解析;同一套消息格式能跑在 stdio、HTTP、甚至 TCP 上(传输层只负责搬字节)。
1.2 三种消息形态
MCP 只有三种消息(docs/specification/draft/basic/index.mdx:31 起)。先看一张对照表:
| 形态 | 有 id? | 有回复? | 用途 |
|---|---|---|---|
| Request(请求) | 是 | 是 | 发起一次操作(如 tools/call) |
| Response(响应) | 是(与请求同 id) | —(它本身就是回复) | 返回结果或错误 |
| Notification(通知) | 否 | 否 | 单向告知,接收方不得回复 |
请求的形状(docs/specification/draft/basic/index.mdx:35):
{
jsonrpc: "2.0";
id: string | number; // 不得为 null;不得和未完成的其它请求重号
method: string; // 如 "tools/call"
params?: { [key: string]: unknown };
}
两条铁律值得记:id 不得为 null(这点比原版 JSON-RPC 更严),且不得复用一个尚未收到响应的 id(docs/specification/draft/basic/index.mdx:46)。
通知没有 id,发出去就不管了——比如 notifications/tools/list_changed(工具清单变了)。
1.3 draft 的新意:每个 result 都带 resultType
这是 draft 相对旧版最显眼的一处改动。成功响应长这样(docs/specification/draft/basic/index.mdx:59):
{
jsonrpc: "2.0";
id: string | number;
result: {
resultType: string; // ← draft 新增的必填字段
[key: string]: unknown;
};
}
resultType 是一个多态结果的判别标签(docs/specification/draft/basic/index.mdx:77),客户端靠它决定怎么解析 result:
"complete"— 请求完成了,result里是最终内容。"input_required"— 请求还没完,服务器需要更多输入;result是一个InputRequiredResult(这正是第 04 章 MRTR 的入口)。- 扩展可以新增取值;客户端遇到不认识的
resultType必须当作非法。
向后兼容的关键一招(docs/specification/draft/basic/index.mdx:85):旧版服务器的响应里没有 resultType,所以客户端必须把“缺失”当成 "complete"。这样新客户端能无痛对接老服务器。
1.4 错误响应与错误码分区
失败时回 error(docs/specification/draft/basic/index.mdx:91):
{
jsonrpc: "2.0";
id?: string | number; // 一般同请求 id;请求烂到读不出 id 时可省
error: { code: number; message: string; data?: unknown; }
}
MCP 沿用 JSON-RPC 标准码(-32700、-32600-32603),并把 JSON-RPC 给“实现自定义”预留的 -32000-32099 重新划了界(docs/specification/draft/basic/index.mdx:113):
| 子区间 | 归谁 | 规则 |
|---|---|---|
-32000 ~ -32019 | 历史遗留 | 新实现不应再用;除 -32002 外不得假设含义 |
-32020 ~ -32099 | MCP 规范专属 | 只有规范能定义;实现不得乱发 |
draft 在专属区里定义了三个新码(docs/specification/draft/basic/index.mdx:129,常量见 schema/draft/schema.ts:426):
| Code | 名字 | 含义 |
|---|---|---|
-32020 | HeaderMismatch | HTTP 头与请求体不一致(见 05 章) |
-32021 | MissingRequiredClientCapability | 处理请求需要某个客户端没声明的能力 |
-32022 | UnsupportedProtocolVersion | 服务器不支持请求声明的协议版本(见 02 章) |
注意 draft 把“资源不存在”的码从旧版的 -32002 改成了标准的 -32602(Invalid Params),但客户端仍应接受老服务器发来的 -32002(docs/specification/draft/server/resources.mdx:406、changelog :37)。