MCP 基础:原语、生命周期、JSON-RPC 基座 本节摘要:MCP 之前的每次集成都是一次性的。模型上下文协议(Model Context Protocol)由 Anthropic 于 2024 年 11 月首发,现由 Linux 基金会旗下的 Agentic AI Foundation 托管,把「发现」与「调用」标准化,使任意客户端都能与任意服务端对话。2025-11-25 规范定义了六大原语(三个在服务端、三个在客户端)、三阶段生命周期、以及 JSON-RPC 2.0 线格式。本节先简要回顾 MCP 是什么(第 12 章 14 节已做概念概览),然后深入这三块基座——吃透它们,本章其余各节就成了阅读理解。
本节摘要:MCP 之前的每次集成都是一次性的。模型上下文协议(Model Context Protocol)由 Anthropic 于 2024 年 11 月首发,现由 Linux 基金会旗下的 Agentic AI Foundation 托管,把「发现」与「调用」标准化,使任意客户端都能与任意服务端对话。2025-11-25 规范定义了六大原语(三个在服务端、三个在客户端)、三阶段生命周期、以及 JSON-RPC 2.0 线格式。本节先简要回顾 MCP 是什么(第 12 章 14 节已做概念概览),然后深入这三块基座——吃透它们,本章其余各节就成了阅读理解。
阅读完本节,你应当能够:
initialize 的**能力协商(Capability Negotiation)**是什么,没有它会断什么。第 12 章 14 节已讲过 MCP 的动机——把「每个 host × 每个 server」的 N×M 定制协议矩阵压成「一套 JSON-RPC 规范」,集成成本从 N×M 降到 N+M。本节不再重复动机,而是钻进规范内部,看清这套标准化协议的具体机制。
MCP 之前,Cursor 有套 MCP 形状但不兼容的工具系统,Claude Desktop 是另一套,VS Code 的 Copilot 扩展是第三套。一个团队做的「Postgres 查询」工具,得为三个 host 各写一遍。复用只能靠拷代码——寒武纪式的一次性集成大爆发,生态速度被压顶。
MCP 用标准化线格式修掉这个问题。一个 MCP 服务端能在每个 MCP 客户端里工作:Claude Desktop、ChatGPT、Cursor、VS Code、Gemini、Goose、Zed、Windsurf,到 2026 年 4 月已有 300+ 客户端、1.1 亿月 SDK 下载、1 万+ 公开服务端。Linux 基金会于 2025 年 12 月在新建的 Agentic AI Foundation 下接管托管。
本章使用的规范版本是 2025-11-25。它新增了异步 Tasks(SEP-1686)、URL 模式 elicitation(SEP-1036)、带工具的 sampling(SEP-1577)、增量 scope 同意(SEP-835)、OAuth 2.1 resource-indicator 语义。第 09~16 节覆盖这些扩展。本节停在基座。
file:///path、db://query/...、自定义 scheme。MCP 里的每个能力,恰好属于这六者之一。第 10~14 节逐一深入。
每条消息是一个 JSON 对象,字段如下:
{jsonrpc:"2.0", id, method, params}。{jsonrpc:"2.0", id, result | error}。{jsonrpc:"2.0", method, params}——无 id,不期望响应。基础规范约 15 个方法,按原语分组。重要的有:
initialize / initialized(握手)tools/list、tools/callresources/list、resources/read、resources/subscribeprompts/list、prompts/getsampling/createMessage(服务端→客户端)notifications/tools/list_changed、notifications/resources/updated、notifications/progress阶段 1 initialize:客户端发 initialize,带 capabilities 与 clientInfo;服务端响应自己的 capabilities、serverInfo、所讲的规范版本;客户端消化完响应后发 notifications/initialized。此后双方都可按协商的能力发请求。
阶段 2 operation:双向。客户端调 tools/list 发现,再 tools/call 调用;服务端若声明了 sampling 能力,可发 sampling/createMessage;工具集变动时服务端可发 notifications/tools/list_changed;用户改 root scope 时客户端可发 notifications/roots/list_changed。
阶段 3 shutdown:任一方关闭传输。MCP 没有结构化的 shutdown 方法,连接结束信号由传输层(stdio 或 Streamable HTTP,见第 09 节)承载。
initialize 握手里的 capabilities 就是契约。服务端示例:
{ "tools": {"listChanged": true}, "resources": {"subscribe": true, "listChanged": true}, "prompts": {"listChanged": true} }
服务端声明它能发 tools/list_changed 通知、支持 resources/subscribe。客户端用自己的一份表示同意:
{ "roots": {"listChanged": true}, "sampling": {}, "elicitation": {} }
客户端若不声明 sampling,服务端绝不能调 sampling/createMessage。对称地,服务端若不声明 resources.subscribe,客户端就不能尝试订阅。
💡 这正是防止生态漂移的机制:不支持 sampling 的客户端仍是合法 MCP 客户端;不调 sampling 的服务端仍是合法 MCP 服务端。它们只是不一起用这个特性。
tools/call 返回一个 content 数组,元素是类型化块:text、image、resource。第 14 节会往这个列表里加 MCP Apps(ui:// 交互式 UI)。
错误用 JSON-RPC 错误码。规范定义的额外项:-32002「Resource not found」、-32603「Internal error」,加上作为 error.data 的 MCP 特定错误数据。
一个常见混淆:capabilities.tools 表示客户端是否支持 tool-list-changed 通知;而客户端会不会调用具体工具,是运行时由它的模型决定的选择,不是能力标志。能力标志是规范级契约,模型的选择与之正交。
JSON-RPC 2.0(2010)是一个轻量双向协议;REST 是客户端发起的。MCP 需要服务端发起的消息(sampling、notifications),所以具有对称请求/响应形状的 JSON-RPC 是天然契合。它还能干净地组合在 stdio 与 WebSocket/Streamable HTTP 之上,无需重造 HTTP 的请求形状。
| 维度 | JSON-RPC 2.0(MCP) | REST | gRPC |
|---|---|---|---|
| 方向 | 双向(服务端可主动发) | 单向(客户端发起) | 双向(流) |
| 信封 | 对称的请求/响应/通知 | HTTP 动词 + 资源 | Protobuf + HTTP/2 |
| 在 stdio 上 | 干净组合 | 不适合 | 不适合 |
| 适合 MCP | 是 | 否(缺服务端发起) | 过重 |
💡 心法:六原语 + 三阶段 + JSON-RPC 2.0——三者咬合,MCP 的一切都建立在此之上。本章后续每一节都是对某一原语或某一扩展的展开。
本节产出 outputs/skill-mcp-handshake-tracer.md——给定一份 pcap 式的 MCP 客户端-服务端交互转录,它为每条消息标注属于哪个原语、哪个生命周期阶段、依赖哪个能力。
code/main.py 造了一个最小 JSON-RPC 2.0 解析器与发射器,然后手把手走 initialize → tools/list → tools/call → shutdown 序列,打印每条消息。无真实传输,只有消息形状。与拓展阅读里的规范对照,即可验证每个信封。
跑解析器:运行 code/main.py,找出能力协商那一行,描述「如果服务端不声明 tools.listChanged 会改变什么」。
加进度通知:扩展解析器处理 notifications/progress,消息形状为 {method:"notifications/progress", params:{progressToken, progress, total}}。在一个长 tools/call 进行中发它,确认客户端处理函数能显示进度条。
通读规范:从头到尾读 MCP 2025-11-25 规范(约 80 页),找出大多数服务端都不需要的那个能力标志。(提示:与资源订阅有关。)
设计新原语:在纸上为假想的「cron 定时任务」特性画出它该归哪个原语。(提示:服务端想让客户端在调度时间调用它。现有六原语都不合适。)MCP 2026 路线图已有相关 SEP 草案。
解析会话日志:从 GitHub 上的某个开源 MCP 服务端解析一段会话日志,统计请求/响应/通知条数,算出生命周期流量与运行时流量的占比。
id+method+params)、响应(id+result|error)、通知(无 id)。initialize 双向声明 capabilities;对方未声明的能力绝不能用——这是防生态漂移的机制。tools/call 返回类型化块数组(text/image/resource,Apps 在第 14 节加)。-32002 资源未找到、-32603 内部错误,加 error.data。capabilities.tools 是「是否支持通知」;调用哪个工具是模型运行时决定,与之正交。下一节,我们动手构建一个 MCP 服务端——用 Python 与 TypeScript SDK,把三大服务端原语用装饰器注册,跑通真实的 initialize 与 tools/call。