MCP 基础:原语、生命周期、JSON-RPC 基座


文档摘要

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 基础:原语、生命周期、JSON-RPC 基座

本节摘要:MCP 之前的每次集成都是一次性的。模型上下文协议(Model Context Protocol)由 Anthropic 于 2024 年 11 月首发,现由 Linux 基金会旗下的 Agentic AI Foundation 托管,把「发现」与「调用」标准化,使任意客户端都能与任意服务端对话。2025-11-25 规范定义了六大原语(三个在服务端、三个在客户端)、三阶段生命周期、以及 JSON-RPC 2.0 线格式。本节先简要回顾 MCP 是什么(第 12 章 14 节已做概念概览),然后深入这三块基座——吃透它们,本章其余各节就成了阅读理解。

学习目标

阅读完本节,你应当能够:

  1. 列全 六大 MCP 原语(服务端:tools、resources、prompts;客户端:roots、sampling、elicitation),各举一个用例。
  2. 走完三阶段生命周期(initialize、operation、shutdown),说清每阶段谁发什么消息。
  3. 解析与生成 JSON-RPC 2.0 的请求、响应、通知三种信封。
  4. 解释 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 节覆盖这些扩展。本节停在基座。

二、从零实现

三个服务端原语

  1. Tools(工具):可调用动作。即第 01 节的四步循环。
  2. Resources(资源):暴露的数据。只读、用 URI 寻址的内容:file:///pathdb://query/...、自定义 scheme。
  3. Prompts(提示):可复用模板。host UI 里的斜杠命令;服务端提供模板,客户端填参数。

三个客户端原语

  1. Roots:服务端被允许触碰的 URI 集合。客户端声明,服务端遵守。
  2. Sampling(采样):服务端请求客户端的模型做一次补全。使服务端能跑 Agent 循环却不需要服务端侧 API key。
  3. Elicitation(征询):服务端在执行中向客户端用户请求结构化输入。表单或 URL(SEP-1036)。

MCP 里的每个能力,恰好属于这六者之一。第 10~14 节逐一深入。

线格式:JSON-RPC 2.0

每条消息是一个 JSON 对象,字段如下:

  • 请求:{jsonrpc:"2.0", id, method, params}
  • 响应:{jsonrpc:"2.0", id, result | error}
  • 通知:{jsonrpc:"2.0", method, params}——无 id,不期望响应。

基础规范约 15 个方法,按原语分组。重要的有:

  • initialize / initialized(握手)
  • tools/listtools/call
  • resources/listresources/readresources/subscribe
  • prompts/listprompts/get
  • sampling/createMessage(服务端→客户端)
  • notifications/tools/list_changednotifications/resources/updatednotifications/progress

三阶段生命周期

阶段 1 initialize:客户端发 initialize,带 capabilitiesclientInfo;服务端响应自己的 capabilitiesserverInfo、所讲的规范版本;客户端消化完响应后发 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 数组,元素是类型化块:textimageresource。第 14 节会往这个列表里加 MCP Apps(ui:// 交互式 UI)。

错误用 JSON-RPC 错误码。规范定义的额外项:-32002「Resource not found」、-32603「Internal error」,加上作为 error.data 的 MCP 特定错误数据。

客户端能力 vs 工具调用细节

一个常见混淆:capabilities.tools 表示客户端是否支持 tool-list-changed 通知;而客户端会不会调用具体工具,是运行时由它的模型决定的选择,不是能力标志。能力标志是规范级契约,模型的选择与之正交。

为什么是 JSON-RPC 而非 REST?

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 解析器与发射器,然后手把手走 initializetools/listtools/callshutdown 序列,打印每条消息。无真实传输,只有消息形状。与拓展阅读里的规范对照,即可验证每个信封。

五、练习

  1. 跑解析器:运行 code/main.py,找出能力协商那一行,描述「如果服务端不声明 tools.listChanged 会改变什么」。

  2. 加进度通知:扩展解析器处理 notifications/progress,消息形状为 {method:"notifications/progress", params:{progressToken, progress, total}}。在一个长 tools/call 进行中发它,确认客户端处理函数能显示进度条。

  3. 通读规范:从头到尾读 MCP 2025-11-25 规范(约 80 页),找出大多数服务端都不需要的那个能力标志。(提示:与资源订阅有关。)

  4. 设计新原语:在纸上为假想的「cron 定时任务」特性画出它该归哪个原语。(提示:服务端想让客户端在调度时间调用它。现有六原语都不合适。)MCP 2026 路线图已有相关 SEP 草案。

  5. 解析会话日志:从 GitHub 上的某个开源 MCP 服务端解析一段会话日志,统计请求/响应/通知条数,算出生命周期流量与运行时流量的占比。

本节要点回顾

  1. 六原语:服务端 tools/resources/prompts;客户端 roots/sampling/elicitation。每个 MCP 能力恰好属于其一。
  2. JSON-RPC 2.0 线格式:请求(id+method+params)、响应(id+result|error)、通知(无 id)。
  3. 三阶段生命周期:initialize(能力协商)→ operation(双向调用)→ shutdown(关传输,无结构化方法)。
  4. 能力协商是契约:initialize 双向声明 capabilities;对方未声明的能力绝不能用——这是防生态漂移的机制。
  5. 结构化内容:tools/call 返回类型化块数组(text/image/resource,Apps 在第 14 节加)。
  6. 错误用 JSON-RPC 码:-32002 资源未找到、-32603 内部错误,加 error.data
  7. 能力 vs 运行时选择:capabilities.tools 是「是否支持通知」;调用哪个工具是模型运行时决定,与之正交。
  8. 选 JSON-RPC 的理由:需要双向(服务端发 sampling/通知),且能干净组合在 stdio 与 HTTP 之上。

下一节,我们动手构建一个 MCP 服务端——用 Python 与 TypeScript SDK,把三大服务端原语用装饰器注册,跑通真实的 initialize 与 tools/call。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U