Model Context Protocol(规范) — 架构与原理
30 秒导读: MCP 是一套开放协议,让一个 AI 应用(比如 Claude Desktop、IDE 里的助手)用统一的接口去接各种外部能力——读文件、查数据库、调 API、跑命令。它规定了“谁连谁、消息长什么样、谁能调用谁、怎么鉴权、怎么保证安全”。本仓库不是某个 SDK 的实现,而是协议本身的权威规范 + 机器可读的 schema。
本文档讲的是 modelcontextprotocol/modelcontextprotocol 仓库里 draft 版规范(协议版本号 LATEST_PROTOCOL_VERSION = "2026-07-28",见 schema/draft/schema.ts:37)。draft 相对已发布的 2025-11-25 做了一次大改造,本文会一路标出“旧版怎样、新版为什么这么改”。
1. 这是什么(零基础也能懂)
一句话定义
MCP(Model Context Protocol,模型上下文协议)是 AI 应用与外部能力之间的标准插头。就像 USB-C 让各种设备用同一个口充电、传数据,MCP 让任何 AI 应用用同一套协议接入任何“工具服务器”。
解决什么问题 / 给谁用
假设你在写一个 AI 助手,想让它能:读用户的本地文件、查公司数据库、发 GitHub PR。
没有 MCP 时,你得为每个能力写一套专属胶水代码——文件一套、数据库一套、GitHub 一套,换个 AI 应用还得重写。
MCP 把这件事标准化:
- 工具作者(写“GitHub 服务器”“数据库服务器”的人)只实现一次 MCP 服务器,所有支持 MCP 的应用都能用。
- 应用作者(写 Claude Desktop、Cursor 这类 host 的人)只实现一次 MCP 客户端,就能接入整个 MCP 生态的服务器。
一句话:M×N 的胶水问题,被 MCP 压成 M+N。
三个角色(先建立画面)
MCP 是 host–client–server 三层结构(docs/specification/draft/architecture/index.mdx:7):
| 角色 | 是谁 | 干什么 |
|---|---|---|
| Host(宿主) | AI 应用本体(Claude Desktop、IDE 插件…) | 管 LLM、管对话历史、管权限、决定要不要批准某个操作 |
| Client(客户端) | host 内部为“连某一个服务器”而 创建的连接器 | 和恰好一个服务器一对一通信,转发消息 |
| Server(服务器) | 一个独立的能力提供方(文件、数据库、API…) | 暴露工具/资源/提示词,专注做好一件事 |
┌──────────────── Host(AI 应用进程)────────────────┐
│ 管 LLM · 管对话 · 管权限 · 管用户授权 │
│ │
│ Client 1 ──────┐ Client 2 ──────┐ Client 3 ──┐│
└──────┼───────────┼──────┼───────────┼──────┼───────┼┘
│ │ │ │ │ │
┌────▼────┐ ┌────▼────┐ … ┌────▼─────────────▼──┐
│ Server │ │ Server │ │ Server │
│ 文件&Git│ │ 数据库 │ │ 远程外部 API │
└─────────┘ └─────────┘ └─────────────────────┘
每个 client ↔ 一个 server,严格一对一;server 之间互相看不见
关键安全设计:一个服务器看不到整段对话,也看不见其他服务器(docs/specification/draft/architecture/index.mdx:101)。完整对话历史只留在 host 手里,跨服务器的交互由 host 统一裁决。这是 MCP 的隔离边界。
用起来什么样(最小直观示例)
一次“让模型查天气”的工具调用,在 MCP 里就是一来一回两条 JSON-RPC 消息——客户端发请求、服务器回结果:
// 客户端 → 服务器:调用名为 get_weather 的工具
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": { "name": "get_weather", "arguments": { "location": "New York" } }
}
// 服务器 → 客户端:返回结果
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
}
],
"isError": false
}
}
(取自 docs/specification/draft/server/tools.mdx:140 与 :156。)就这么朴素——MCP 的全部威力来自“把所有交互都收敛成这种标准消息”。
一句话直觉/类比
- MCP 之于 AI 应用,约等于 USB-C 之于硬件、LSP 之于编辑器:定义统一接口,让两边各自独立演化、随意组合。
- 三件服务器能力可以这样记:Tools = 给模型用的手(模型自己决定调)、Resources = 喂给模型看的资料(应用决定塞什么)、Prompts = 给用户点的快捷指令(用户主动选)。
本节不碰底层。记住三角色 + 一来一回的消息,就可以往下读了。
2. 顶层全景(它大概怎么转)
协议由哪几块拼成
MCP 规范把自己拆成几层,底下两层人人必须实现,上面按需选(docs/specification/draft/basic/index.mdx:9、:17):
| 层 | 是什么 | 必须吗 | 本文第几章 |
|---|---|---|---|
| Base Protocol | JSON-RPC 消息类型(请求/响应/通知) | 必须 | 01 |
| Versioning & 消息模式 | 版本协商、扩展协商、三种消息模式 | 必须 | 02、04 |
| Server Features | Tools / Resources / Prompts | 按需 | 03 |
| Client Features | Sampling / Elicitation / Roots | 按需 | 04 |
| Authorization | HTTP 传输上的 OAuth 鉴权 | 按需 | 06 |
| Utilities | 补全、分页、缓存等横切关注(注:Logging 旧属此层,draft 已废弃,见下文) | 按需 | 03/05 |
一处与废弃主线相关的提醒:旧版把 Logging 当作常规 Utility,但 draft 已把它和 Sampling/Roots 一并废弃(
docs/specification/draft/changelog.mdx:73,SEP-2577),并移除了logging/setLevel方法(changelog:20)。建议改用 stderr(stdio)或 OpenTelemetry。本文凡提到日志处都按此理解。
一张全景图:一次工具调用怎么流动
怎么读这张图:从左到右是“用户想做事 → host 让 LLM 决策 → client 发请求 → server 干活 → 结果回流”。
用户 Host (AI 应用) Client Server
│ “帮我查天气” │ │ │
├───────────────────────►│ │ │
│ 把工具清单喂给 LLM,LLM 决定调 get_weather │
│ ├─────────────────────►│ │
│ │ tools/call ├────────────────►│
│ │ (带 _meta:版本/身份/能力) │ 执行
│ │ │◄────────────────┤
│ │◄──────────────────────┤ 结果 content │
│◄───────────────────────┤ 把结果给 LLM 续写,渲染给用户 │
每条请求都带一段 _meta,里面塞了协议版本、客户端身份、客户端能力——这是 draft 版的核心,下一节展开。
draft 版的一句话主线:从“有会话”改成“无状态”
这是理解整份规范最重要的一件事。
旧版(2025-11-25 及更早):客户端先发 initialize 握手,双方协商版本与能力,建立一个会话/连接级状态,之后的请求都默认沿用这个状态。
draft 版(2026-07-28):取消握手。每个请求自带版本、身份、能力(放在 _meta 里),服务器独立处理每一条请求,不依赖任何“上一条请求留下的状态”(docs/specification/draft/basic/index.mdx:182)。
旧版(有状态会话): draft(无状态):
initialize ───► (没有握手)
◄── 协商结果 每条请求都自带:
tools/call ───► _meta = { 版本, 身份, 能力 }
tools/call ───► 服务器把每条都当“第一次见”来处理
(都复用会话状态)
为什么这么改?为了能水平扩展、随便挂负载均衡。 无状态意味着任意一台服务器实例都能处理任意一条请求,不需要“粘性会话”,崩了重来也不丢上下文。代价是每条请求都得重复带元数据。
这次改造连带产生了一串新机制,本文逐章讲:server/discover(02)、MRTR(04)、subscriptions/listen(05)、resultType(01)。完整清单见 docs/specification/draft/changelog.mdx:11。
怎么读这套文档(阅读地图)
建议顺序就是章节顺序,由浅入深:
- 01 JSON-RPC 与消息 — 地基。不懂消息形态,后面都看不懂。
- 02 版本与发现 — 无状态后,双方靠什么“对上话”。
- 03 服务器三件套 — Tools/Resources/Prompts,MCP 最常用的部分。
- 04 MRTR 与客户端能力 — 全协议最巧妙的一章:无状态下服务器怎么“反过来问客户端”。
- 05 传输层 — stdio 和 Streamable HTTP 两种管子。
- 06 鉴权与安全 — OAuth 模型 + 贯穿全协议的安全红线。
如果你只想抓重点:读完本页 + 04 章(MRTR)就理解了 draft 版的灵魂。
设计哲学(贯穿全协议的四条)
MCP 的所有取舍都能回溯到四条设计原则(docs/specification/draft/architecture/index.mdx:84):
- 服务器要极易编写 — 复杂的编排(管 LLM、管对话、管权限)全压给 host,服务器只管暴露能力。
- 服务器要高度可组合 — 每个服务器独立、聚焦,多个能无缝叠加。
- 服务器看不到整段对话,也看不见别的服务器 — 隔离即安全边界。
- 能力可渐进添加 — 核心协议极简,额外能力靠协商解锁,新旧可共存。
读后续任何机制时,都可以问一句“这是为了满足上面哪条原则?”——通常一问就通。
代码地图(导航索引)
| 主题 | 文件路径 | 符号 / 锚点 |
|---|---|---|