MCP 协议详解——AI 应用的标准化连接层

本文为「AI Agent 技术系列」第 3 篇。Function Calling(第 2 篇)解决了”模型如何决定调用工具”,MCP 解决”工具如何被标准化接入”。

2026-07-29 重要更新:MCP 官方于 2026-07-28 发布了新版规范 [1][2]。这次改动很大——协议核心从”双向有状态”转为”请求/响应无状态”,核心维护者称其为远程 MCP 上线以来最重要的一次发布。本文已按新协议全面重写,并保留新旧协议对比,方便已有实现的读者评估迁移。

一、主题定义与背景

MCP 的正式定义

MCP 官方文档的定义 [4]:

“Model Context Protocol (MCP) 是一个用于连接 AI 应用与外部系统的开源标准。通过 MCP,Claude、ChatGPT 等 AI 应用可以连接数据源(如本地文件、数据库)、工具(如搜索引擎、计算器)和工作流(如专用提示模板),从而获取关键信息并执行任务。”

USB-C 类比:从 N×M 到 N+M

1
2
3
4
5
6
7
传统模式(N×M 集成):
N 个 AI 应用 × M 个工具 = N×M 个集成接口
每个工具为每个 AI 应用单独开发连接

MCP 模式(N+M 集成):
N 个 AI 应用 → MCP 协议 ← M 个工具
一次对接,处处可用

就像 USB-C 让充电这件事变得简单统一——一个标准协议,让 AI 连接所有数据源和工具。

提出背景与现状

MCP 由 Anthropic 于 2024 年 11 月发布,旨在解决 AI 工具集成的碎片化问题。截至 2026-07-28 版本发布时,官方 Tier 1 SDK 月下载量已接近 5 亿次,TypeScript 和 Python SDK 累计下载均突破 10 亿次 [2],已被 Claude、ChatGPT、VS Code、Cursor 等主流 AI 应用和开发工具采用。

当前最新规范版本为 2026-07-28 [1],其核心变化是:MCP 从一个双向有状态协议,转变为请求/响应式的无状态协议。按官方的说法,这是开发者呼声最高的改进之一——大家要的是更可靠、更容易水平扩展的 MCP Server 部署方式 [2]。


二、核心架构:不变的部分

新协议改变的是”通信方式”,而三角色架构、三类原语这些概念骨架在 2026-07-28 中依然成立。

2.1 三角色架构

graph TB
    subgraph Host主机
        H[AI 应用<br/>如 Claude / VS Code]
        C1[Client 1<br/>连接器]
        C2[Client 2<br/>连接器]
    end

    S1[MCP Server 1<br/>本地文件系统]
    S2[MCP Server 2<br/>远程数据分析]

    H --> C1
    H --> C2
    C1 <-->|MCP协议| S1
    C2 <-->|MCP协议| S2
角色 职责 示例
Host(主机) AI 应用本身,用户直接面对的程序,负责统筹多个连接 Claude Desktop、VS Code、Cursor
Client(客户端) 主机内部的”连接器”,每个客户端与一个服务器保持专用连接 主机内嵌入的 MCP Client 实例
Server(服务器) 提供数据或工具的程序,可运行在本地或云端 文件系统 Server、GitHub Server、数据库 Server

关键设计:一个 Host 可同时连接多个 Server——例如 VS Code 可以同时连接本地文件系统 Server 和远程数据分析 Server。

2.2 三类核心原语

Server 通过三类原语为 LLM 提供上下文,这在新旧协议中保持一致 [1]:

原语 控制方 描述 示例
Prompts(提示) 用户控制 预定义的提示模板,用户主动选择 “代码审查”提示模板
Resources(资源) 用户控制 可读取的数据源,类似 GET 端点 文件内容、数据库记录
Tools(工具) 模型控制 可执行的函数,类似 POST 端点 发送邮件、创建文件

关键区别:Prompts 和 Resources 由用户控制(用户决定何时使用),Tools 由模型控制(AI 自主决定何时调用)。

注意:客户端侧的三个特性 Roots、Sampling、Logging 在 2026-07-28 中已被标记为弃用(详见第四节),新实现不应再采用。

2.3 传输方式

传输方式 状态 说明 适用场景
stdio 活跃 通过标准输入/输出通信 本地 Server(如文件系统访问)
Streamable HTTP 活跃(2026-07-28 大改) 无会话、每个请求自描述,必须携带 Mcp-Method / Mcp-Name 远程 Server(如云端 API)
HTTP+SSE 正式弃用 2025-03-26 起被 Streamable HTTP 取代,2026-07-28 正式进入弃用生命周期 [3] 仅存量兼容

三、2026-07-28 新协议核心:无状态化

3.1 为什么要去掉会话

旧协议(2025-11-25 及之前)是有状态的:Client 与 Server 先经过 initialize/initialized 握手交换版本与能力,之后所有请求都携带 Mcp-Session-Id,绑定到同一个会话。这带来两个工程问题:

  1. 难以水平扩展:负载均衡器必须把同一会话的请求路由到同一实例(或依赖共享存储同步会话状态);
  2. 可靠性差:会话中断即上下文丢失,Server 重启、连接闪断都需要额外的恢复逻辑。

新协议的答案是:每个请求自描述(self-describing),任何请求可以落在任意实例上,一个普通的轮询(round-robin)负载均衡器就能撑起 MCP Server 集群,无需共享存储 [2]。

3.2 无握手、无会话:请求自带身份与能力

2026-07-28 正式移除了 initialize/initialized 握手和 Mcp-Session-Id 头(SEP-2575、SEP-2567)。每个请求在 _meta 中自带协议版本、客户端身份和客户端能力 [2][3]:

1
2
3
4
5
6
7
8
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search","arguments":{"q":"otters"},
"_meta":{"io.modelcontextprotocol/clientInfo":{"name":"my-app","version":"1.0"}}}}

配套机制:

  • server/discover:新增的 RPC,Server 必须实现,用于声明支持的协议版本、能力和身份。Client 可以在首次请求前调用它做版本协商,也可以完全不调用——它是可选的,还可作为 stdio 场景下的向后兼容探测 [3];
  • 版本不匹配:返回 UnsupportedProtocolVersionError,而不是握手失败;
  • 应用层状态怎么办:去掉协议级会话不代表应用必须无状态。如果 Server 需要跨调用维持状态,官方推荐由工具显式铸造(mint)一个句柄(handle)返回给模型,模型在后续调用中把句柄作为普通参数传回。相比藏在传输层里的会话状态,模型能”看见”这个句柄并在工具间传递它,实践效果更好 [2]。
sequenceDiagram
    participant C as Client
    participant LB as 负载均衡器
    participant SA as Server 实例 A
    participant SB as Server 实例 B

    C->>LB: (可选)server/discover
    LB->>SA: 转发到任意实例
    SA-->>C: 协议版本 / 能力 / 身份

    C->>LB: tools/call(_meta 自带版本+能力+身份)
    LB->>SB: 任意实例均可处理,无需会话亲和
    SB-->>C: resultType: "complete"

3.3 MRTR:无状态协议下的”服务器反问”

旧协议中,Server 可以主动向 Client 发起请求——elicitation/create(向用户要补充信息)、sampling/createMessage(请求模型采样)、roots/list(查询根目录),这要求一条常开的双向流。

新协议用 Multi Round-Trip Requests(MRTR,SEP-2322) 取代这套机制:当工具执行到一半需要用户确认或补充参数时,Server 不再”反向调用”,而是返回一个中间结果 resultType: "input_required",把需要的信息放在 inputRequests 中;Client 处理后重试原始调用,把答案附在 inputResponses 里 [2][3]。

sequenceDiagram
    participant U as 用户
    participant C as Client
    participant S as Server

    C->>S: tools/call create_project
    S-->>C: resultType: "input_required"<br/>inputRequests: [请确认预计费用]
    C->>U: 展示确认弹窗
    U-->>C: 确认
    C->>S: 重试 tools/call(附 inputResponses)
    S-->>C: resultType: "complete"

配套地,所有结果现在都必须携带 resultType 字段:普通结果为 "complete",MRTR 中间结果为 "input_required"。对接旧版 Server 时,缺失该字段的结果一律按 "complete" 处理 [3]。

Supabase 是个现成的例子:它的 MCP Server 一直以无状态方式运行,旧协议下想支持 elicitation 就得先把架构改成有状态,一直没做;MRTR 出来后,它可以在创建项目前向用户确认费用、在删除数据前二次确认了 [2]。

3.4 Header 路由:网关不再解析 JSON

Streamable HTTP 请求现在必须携带 Mcp-MethodMcp-Name 头(SEP-2243)。网关、限流器、WAF 可以直接基于 HTTP 头做路由、鉴权和计量,不必解析 JSON 请求体 [2][3]。工具参数还可以通过 x-mcp-header 映射为自定义头。

3.5 列表结果可缓存

tools/listprompts/listresources/listresources/readresources/templates/list 的响应现在必须携带 ttlMs(新鲜度提示,毫秒)和 cacheScope"public" / "private",控制共享中间层能否缓存)两个字段(SEP-2549)[3]。

同时规范建议 Server 以确定性顺序返回工具列表。这两点组合起来有一个直接收益:客户端可以缓存工具目录,且重连后工具清单顺序稳定,上游 LLM 的 prompt cache 命中率不会因为重连而失效 [2][3]。

3.6 subscriptions/listen:统一的通知流

旧协议通过 HTTP GET 端点和 resources/subscribe/resources/unsubscribe 接收服务器变更通知。新协议将其收敛为单一的 subscriptions/listen 长连接流,Client 按通知类型显式 opt-in(toolsListChangedpromptsListChangedresourcesListChangedresourceSubscriptions)[3]。

与请求相关的通知(如 notifications/progress)仍在原请求的响应流上传输,不走 subscriptions/listen。另外,SSE 的断流重放机制(Last-Event-ID)被移除——断流即丢失在途请求,Client 应以新的请求 ID 重新发起 [3]。

3.7 扩展框架:Tasks、MCP Apps、EMA

2026-07-28 正式确立了扩展(extensions)框架,ClientCapabilitiesServerCapabilities 新增 extensions 字段。核心协议保持精简,增值能力以官方扩展形式演进 [2][3]:

扩展 说明
Tasks(io.modelcontextprotocol/tasks 长时任务从实验性核心移入官方扩展:阻塞式 tasks/result 被轮询式 tasks/get 取代,新增 tasks/update 支持客户端向任务补充输入(SEP-2663)
MCP Apps 在 AI 客户端内运行的交互式应用
Enterprise Managed Authorization(EMA) 企业托管授权

四、新旧协议对比与迁移指南

4.1 核心对比表

维度 2025-11-25(旧) 2026-07-28(新)
协议模型 双向、有状态 请求/响应、无状态
连接建立 initialize/initialized 握手 + Mcp-Session-Id 无握手无会话,_meta 自带版本、能力、身份
能力发现 握手时交换 可选的 server/discover RPC
服务器发起交互 elicitation/createsampling/createMessageroots/list(需常开双向流) MRTR:resultType: "input_required" + 重试携带 inputResponses
HTTP 路由 网关需解析 JSON 体 必须携带 Mcp-Method / Mcp-Name 头,按头路由
列表缓存 无缓存语义,结果可能随连接变化 ttlMs + cacheScope,确定性排序
变更通知 HTTP GET 端点 + resources/subscribe 单一 subscriptions/listen 流,按类型 opt-in
断流恢复 Last-Event-ID 重放 移除重放,以新请求 ID 重发
长时任务 实验性核心,阻塞式 tasks/result 官方扩展,轮询 tasks/get + tasks/update
客户端注册 Dynamic Client Registration(DCR) Client ID Metadata Documents(CIMD),DCR 弃用
Roots / Sampling / Logging 核心特性 弃用(至少 12 个月过渡窗口)
弃用政策 无正式政策 正式特性生命周期:Active → Deprecated → Removed,最短 12 个月弃用窗口

4.2 弃用清单与官方迁移建议

2026-07-28 同时确立了正式的特性生命周期政策(SEP-2596):被弃用特性至少保留 12 个月,让团队可以有计划地升级,而不是被动应对 [2][3]。本次弃用及官方建议的替代方案 [3]:

弃用特性 官方迁移建议
Roots 通过工具参数、资源 URI 或服务器配置传递目录/文件
Sampling 直接集成 LLM 提供商 API
Logging stdio 场景写 stderr,或使用 OpenTelemetry(新协议已规范 traceparent_meta 键的传播约定)
HTTP+SSE 传输 迁移到 Streamable HTTP
DCR 客户端注册 迁移到 CIMD(DCR 保留向后兼容)
协议级会话 工具显式铸造句柄,模型作为参数传递

4.3 SDK 支持情况

TypeScript、Python、Go、C# 四个 Tier 1 SDK 在规范发布当天即支持 2026-07-28,Rust SDK 处于 beta 支持阶段。官方提供了针对破坏性变更的迁移说明,重度依赖会话标识的实现迁移成本相对较高 [2]。


五、安全机制与授权演进

5.1 六大安全威胁详解

威胁 说明 防御方案
冒充攻击 攻击者冒充已授权用户,利用系统记住的权限 Token 绑定到特定请求上下文
令牌泄露 Server 把数字钥匙直接转手给别人,不检查合法性 令牌绑定颁发者,禁止跨授权服务器复用 [6]
SSRF 攻击 恶意 Server 诱导 AI 访问不该访问的内部系统 拦截内网请求,限制出站目标
会话劫持 攻击者偷走会话标识,冒充你与系统交互 新协议已移除协议级会话,从根源上缩小了这一攻击面
本地入侵 安装了恶意 MCP Server,在电脑上搞破坏 沙箱运行 + 来源确认
权限过大 一次性申请太多权限,一旦泄露后果严重 最小权限原则 + 定期审查

无状态化对安全也有直接影响:上表中的”会话劫持”,以及跨 session 复用令牌这类依附于长会话的攻击,在没有协议级会话之后就失去了着力点。这不是新协议专门做的安全设计,但确实是移除会话带来的附带收益。

工具投毒攻击(Tool Poisoning Attack)

2025 年 3 月,Invariant Labs 披露了一种新型攻击 [7]:

1
2
3
4
5
6
7
8
9
攻击原理:
1. 恶意 MCP Server 在工具描述中注入隐藏指令
2. AI 读取工具描述时,恶意指令被注入到上下文
3. AI 被诱导执行非预期操作(如泄露敏感数据)

防御方案:
- 工具描述签名验证
- 限制工具描述长度
- 对工具描述进行内容安全审查

OWASP 已发布 MCP Top 10 安全风险清单,其中 MCP01:2025 就是”令牌管理不当与密钥暴露” [6]。另外我的一个推测:新协议要求工具列表确定性排序之后,工具描述如果被中途篡改,客户端做前后比对会比以前容易——但这属于实现层面的机会,规范本身没有把它作为安全特性来承诺。

5.2 OAuth 2.1 授权机制六步详解

MCP 遵循 OAuth 2.1 标准——经过验证的行业安全方案,不是自己发明的”土办法” [1]。

flowchart LR
    A[① 询问身份<br/>Client尝试连接] --> B[② 获取清单<br/>Server告知授权位置]
    B --> C[③ 用户授权<br/>浏览器弹窗确认]
    C --> D[④ 登记注册<br/>Client提供身份标识]
    D --> E[⑤ 获取凭证<br/>颁发Token通行证]
    E --> F[⑥ 验证通行<br/>每次请求出示Token]
步骤 说明
① 询问身份 客户端尝试连接,服务器要求”请先证明你是谁”
② 获取清单 服务器告诉客户端需要到哪里获取授权
③ 用户授权 浏览器弹出页面,用户确认”是的,我允许这个操作”
④ 登记注册 客户端向授权服务器提供身份标识(新协议下首选 CIMD)
⑤ 获取凭证 授权服务器颁发”数字通行证”(Token)
⑥ 验证通行 每次请求都出示通行证,服务器验证是否有效

5.3 2026-07-28 的授权强化

官方坦言,授权是实现者花费集成时间最多的环节。新版规范做了四项硬化 [2][3]:

  1. RFC 9207 颁发者校验:授权服务器应在授权响应中返回 iss 参数,客户端必须在兑换授权码前校验它与记录的颁发者一致(SEP-2468),堵住”授权服务器混淆”漏洞;
  2. application_type 声明:客户端注册时必须声明合适的 application_type,解决桌面/CLI 应用 localhost 重定向被授权服务器拒绝的问题(SEP-837)——如果你的 CLI 客户端 OAuth 流程报过 redirect_uri 错误,多半就是这个原因;
  3. 凭证绑定颁发者:客户端凭证必须按颁发者标识持久化,禁止跨授权服务器复用,授权服务器变更时必须重新注册(SEP-2352);
  4. DCR → CIMD:动态客户端注册(DCR)正式弃用,转向 Client ID Metadata Documents(CIMD)。DCR 保留向后兼容,但将在未来版本移除。

六、实际应用场景

场景一:本地文件系统 MCP Server(stdio 传输)

以下示例基于 TypeScript SDK 的经典写法。SDK v2 已随 2026-07-28 规范发布(采用客户端/服务端拆分的新架构),从 1.x 迁移请参考官方迁移说明 [2]。stdio 场景下,新协议以 server/discover 作为向后兼容探测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// npm install @modelcontextprotocol/sdk

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { readFile, writeFile } from "fs/promises";

const server = new Server(
{ name: "filesystem-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);

// 注册工具
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;

switch (name) {
case "read_file": {
const content = await readFile(args.path, "utf-8");
return { content: [{ type: "text", text: content }] };
}
case "write_file": {
await writeFile(args.path, args.content);
return { content: [{ type: "text", text: `已写入 ${args.path}` }] };
}
}
});

// 使用 stdio 传输
const transport = new StdioServerTransport();
await server.connect(transport);

场景二:需要跨调用状态的企业集成——显式句柄模式

新协议去掉了协议级会话,但企业场景(如 CRM 多步查询)常需要跨调用状态。官方推荐的模式是工具显式铸造句柄 [2]:

1
2
3
4
5
6
7
8
9
10
旧协议做法:
状态藏在 Mcp-Session-Id 背后,模型不可见
负载均衡必须做会话亲和

新协议做法:
① 工具 open_customer_session 返回 { "handle": "cs_8f3a..." }
② 模型在后续 tools/call 中把 handle 作为普通参数传回
③ Server 按 handle 从自己的存储中恢复状态
优点:模型"看得见"句柄,能自主在工具间传递;
任意实例都能处理请求(状态在存储层而非连接层)

安全最佳实践四原则

原则 说明 实践要点
信任但要验证 收到的令牌必须检查是否过期、颁发者是否匹配 校验 iss,凭证按颁发者隔离存储
最小权限 一开始只申请最少权限,需要更多时再临时申请 定期审查并撤销不必要的权限
安全通信 生产环境务必使用 HTTPS,绝不记录密码和令牌 拦截发往内网的请求(防 SSRF)
本地防护 安装 MCP Server 前确认来源可信 在沙箱中运行,执行操作前向用户展示具体命令

七、行业趋势与生态

无状态化的产业落地

2026-07-28 发布当天即获得大量平台支持 [2]:

平台 落地方式
AWS Amazon Bedrock AgentCore 支持无状态核心部署 MCP Server;Tasks 扩展由 AWS 贡献
Cloudflare Agents SDK 首日支持,MCP Server 可直接跑在 Workers 上,无传输会话开销
Google Cloud 在其开发者工具生态中采用新规范
Microsoft Foundry 的统一 MCP 端点结合无状态操作、Tasks 与企业托管身份
Netlify / Supabase / Figma 等 无状态部署 + MRTR 支持 elicitation 场景

社区框架同步跟进:FastMCP 4.0 提供后台任务、无状态交互与企业授权的一等支持;mcp-use 基于新 SDK v2 的客户端/服务端拆分,包体积缩减约 83%、速度提升约 25% [2]。

MCP vs OpenAI Plugins vs Custom Tools

方案 定位 优势 劣势
MCP 开放标准协议 跨平台通用;无状态化后可按普通 HTTP 负载运维 破坏性升级需要迁移成本
OpenAI Plugins OpenAI 生态专用 与 ChatGPT 深度集成 仅限 OpenAI 生态
Custom Tools 自定义集成 完全可控 无法复用,开发成本高

Cloudflare 对这次发布的评价我认为说到了点子上:让 Agent 基础设施”像 Web 的其他部分一样工作——无状态、可缓存、可路由” [2]。一个协议能被普通负载均衡器、CDN 和 WAF 直接处理,才谈得上是基础设施;在此之前,MCP 更像一个需要专门伺候的特殊工作负载。


结论

MCP 的核心价值在于标准化——用一个协议替代无数个定制集成。2026-07-28 版本在此之上补齐了可运维性:无状态核心让 MCP Server 可以像普通 Web 服务一样水平扩展。对于技术决策者:

  1. 新项目直接上新协议:不用管握手和会话粘性,工具目录还能缓存,部署运维都比旧协议省事;Roots、Sampling、Logging 和 HTTP+SSE 这些已弃用特性不要再采用
  2. 存量项目评估迁移:官方承诺至少 12 个月的弃用窗口,不必恐慌,但两件事要排上日程——去除对 Mcp-Session-Id 的依赖(改用显式句柄),以及把服务器发起的请求改造为 MRTR
  3. 安全仍需主动防御:工具投毒、SSRF、令牌管理不当依然是真实威胁;新协议的 iss 校验、凭证绑定颁发者等硬化措施应尽快落地

从 Function Calling(第 2 篇)到 MCP,工具集成正在从”各自为政”走向”标准统一”。这次无状态化之后,MCP 离”可规模化运维的基础设施”也近了一大步。


参考资料

[1] Model Context Protocol Specification (2026-07-28). 2026-07-28

[2] The 2026-07-28 Specification - MCP 官方发布博客. 2026-07-28

[3] MCP 2026-07-28 Key Changes(官方 Changelog). 2026-07-28

[4] What is the Model Context Protocol (MCP)?. 2026-07-28

[5] Model Context Protocol Specification (2025-11-25). 2025-11-25

[6] OWASP MCP Top 10 - MCP01:2025 Token Mismanagement. 2026-05-11

[7] MCP 工具投毒攻击(Tool Poisoning Attack). 2025-09-13

[8] MCP CVE Project