MCP(模型上下文协议),前段时间发布了最新版的规范。
之前曾有人惊呼“MCP is dead”,因为有公司放弃了 MCP,转而使用 API 或 CLI 来连接企业系统。不过事实证明,MCP 当前仍然是 Agent 连接外部世界最重要也最通用的方式。
新版规范放弃了一些晦涩无用的功能,并结合社区反馈,特别是企业场景中的真实需要,做了多项重要重构。
下面为你解读新版 MCP 协议中,小编认为最重要的三个变化及相关对比:
-
会话:协议级的无状态化
-
MRTR:多轮交互,一次请求
-
Tasks:持续的后端工作任务
-
MCP与A2A:都有 Task,区别在哪里
01 会话:协议级的无状态化
如果你经常需要编写 MCP Server,比如连接企业的 ERP,那么了解 MCP 客户端与服务端的交互机制有助于你更好的控制会话过程。
旧版本:用会话 ID 实现有状态交互
在之前的有状态 Streamable HTTP 中,客户端先发送 initialize,交换协议版本与能力;然后服务端在响应中签发 Mcp-Session-Id,客户端再确认 initialized。随后的每次请求都会携带该会话 ID,用来关联上下文。
大致如下:

这种模式下,一次会话可以跨多次 HTTP 连接,并用会话 ID 实现关联。
旧版也允许不使用会话 ID 的无状态模式,但initialize 仍然是必须的。
新版本:无状态,每个请求独立处理
新的 MCP 协议把客户端与服务端的交互彻底“无状态化”,因此 Mcp-Session-Id也就没存在的必要,而且也去掉了 initialize 的握手过程。
那么考虑到兼容性,如何让双方能交换协议版本和能力呢?答案是在每个请求的_meta 字段中自带协议版本和能力。

简单的说,现在调用 MCP 工具就像调用 Restful API 一样简单。但注意,协议级的无状态并不意味着你不能在服务端保存共享的状态信息。
无状态协议在控制上要简单的多,但也有代价:
-
好处:最大好处是简化会话管理。比如当扩容、负载分担、切换实例时,不必考虑会话同步,也不用依赖会话“黏性路由”等。
-
代价:重复携带版本等元数据,且“有状态”需要自行实现。比如,跨多次请求的上下文、访问权限控制等;无状态的 Tool 也同样要考虑幂等这样的问题。
“有状态”如何自行实现?
MCP 服务端可把必要的上下文(比如业务信息)存入服务端的数据库或缓存,返回一个业务句柄(ID);客户端在后续工具参数中再显式携带它。这个句柄关联的通常是某项业务工作内容,而非客户端与服务器之间的整段会话。比如:

-
CRM 助手先调用 create_review 工具
-
实例 A 保存必要的业务数据和规则,返回 reviewId
-
随后调用 update_review 工具时,带上同一 reviewId
-
虽然命中实例 B,但工具仍然可以用 reviewId 读取到之前的状态数据
02 MRTR: 多轮交互,一次请求
当 MCP 工具执行到一半,发现还缺一些信息怎么办?
比如有个业务方案需要用户选择,或者提交前由于安全管控需要获得许可。此时应该如何补齐这些信息,让服务端操作继续呢?
MRTR 就是让 MCP Server 能够处理此类多轮交互,以补充信息的一种机制。
旧版本:服务端发起补充输入请求
旧版的 MCP 存在一种中途询问用户的方法 — 通过发送 elicitation/create 请求,客户端展示表单,并把用户答复再返回给服务端继续原操作。
这意味着客户端在等待工具执行结果的同时,需要处理 MCP Server 发来的另一条请求并返回答复;而服务端也在原工具的执行上下文中等待到答复,并恢复原处理过程,最后返回结果。
注意,整个过程都属于一次工具调用:

给这种机制打个比方:
你去柜台办事,办到一半发现缺少资料。柜台人员保留着你的办理进度,请你补充。这笔业务暂时挂起,等你交来资料后,接着办完。
新的 MCP 协议对此进行了改进,更好地配合上一节的无状态请求模式。
新版本:先返回“需要输入”,再重试原调用
MRTR 是 Multi Round-Trip Requests,它的机制是:
把“还需要补充信息”变成正式的中间结果,并结束本次工具请求;而你的答复则继续发起新的请求即可。
流程如下:

-
第一次请求:MCP Server 返回 resultType 为 input_required 的结果,在 inputRequests 中列出待补充信息,告诉客户端“需要你补充xx信息”。
-
客户端将答复整理为 inputResponses,并用相同的键对应原来的问题;如果服务端还返回了 requestState(中间状态),客户端将它原样带回;
-
第二次请求:客户端携带原参数、inputResponses 及 requestState,发起新的请求,服务端继续处理,完成后返回 complete;如果还缺信息,也可以继续下一轮。
继续上面的比方:
你去柜台办事,办到一半发现缺少资料。柜台人员给你一张补件单和办理回执,这一轮办事就结束了。你补齐资料后,带着回执再次来办理,接待人员根据回执恢复进度,继续帮你处理完。
这样做的好处是:
每一轮交互都是一次独立的请求,客户端可以先结束本轮请求,等到取得答复后再继续;而服务端也无需保留原来的响应流。
代价也很明显:两边都要实现“续传”的逻辑 — 客户端要能够理解 input_required ;服务端也要能够恢复某个请求上下文,并控制重复提交等边界问题。
中间状态:requestState
这种机制下的中间状态(“办理回执”)是如何保存和传递的呢?
服务端可以用 requestState 把这种状态返回客户端,下次客户端原样回传即可(这也是无状态会话的代价);而服务端在接收到 requestState 后,首先需要检验完整性、有效期等,然后恢复,并进行后续处理。
03 Tasks:持续的后端工作任务
Tasks 是 MCP 服务端运行长时任务的一种机制(比如,需要 MCP Tool 完成一个长达10分钟的数据统计分析任务)。
这种服务端的长时任务,通常有一些典型问题:
-
异步,即不能让客户端阻塞等待
-
如果客户端不等待,后续如何获得任务结果
-
客户端如何查看处理状态,又如何取消
这就是 MCP Tasks 试图解决的问题。
在最新的 MCP 规范中,Tasks 已经被作为官方的正式扩展之一(我们曾经介绍过另一个扩展:MCP Apps)纳入。
Tasks 的执行方式
如果MCP 的客户端与服务端都明确支持这项扩展,那么就可以按照如下方式使用 Tasks:

-
客户端调用 MCP 工具,服务端决定以 Task 方式处理该任务
-
服务端返回 resultType 为 task 的结果,并返回 taskId、状态和时间等信息,表示任务已经受理。
-
客户端自行保存 taskId,随后可以通过 tasks/get 查询任务状态;当任务完成后(completed),可以从查询结果中取得最终的任务结果。
这是一个完整的交互时序:

Tasks 的补输入、取消与完成
Tasks 也允许任务中途补充输入 — 你可以通过 tasks/update 提交补充的信息(如果收到 input_required 的指示)。
Tasks 还允许中途取消任务 — 通过 tasks/cancel 调用进行“协作式取消”。但注意,任务不保证立即停止,更不等于自动回滚已经写入的数据。
最终,当收到的任务状态为 completed 时,表示任务完成。
需要注意的是,完成不等于成功。MCP 服务端仍可能通过 isError 标志表示任务失败;而 failed 才表示任务发生了系统级错误(未完成)。
通过订阅获取状态:让 Tasks 主动报告变化
前面使用 tasks/get 查询 Tasks 状态,在客户端通常对应轮询机制。但还有一种方法可以更实时的获取 Tasks 状态 — 通过订阅接收状态通知。即:
客户端告诉服务端自己关注的 Tasks,服务端在其状态变化时通知客户端。
大致过程如下:

这里推送的内容不只是简单的“completed”或者“working”的信号,而是与调用 tasks/get 所能获得的内容一致的完整任务快照。
任务进入 completed 状态时,通知中会包含最终结果,客户端可以直接读取,无须再查询一次;如果任务返回 input_required,客户端也能及时的通过 tasks/update 提交答复,让任务继续。
以上就是 Tasks 的核心能力了。
Tasks 的好处很明显:客户端无需阻塞等待,后续通过 TaskId 回来查看即可;而代价则发生在 MCP Server 侧,队列、持久存储、故障恢复、幂等,都需要考虑,当然这会由 SDK 代劳。
Tasks 是“协议无状态,但任务可以有状态”的体现;既简化了协议,又通过扩展保留了部分特殊任务需要的能力。
04 MCP 与 A2A:都有 Task,区别在哪里?
有了 Tasks、多轮补充输入和状态通知,MCP 已经能够接入较完整的后端工作。让我们想象下:
如果我们把一个 Agent 放在后端负责任务执行,并把它通过 MCP Tool 向另一个 Agent 开放,那么就可以完美的实现两 Agent 之间的协作。

这让MCP 的 Tasks 与 A2A 出现了明显重叠:两者都可以实现 Agent 之间的互操作 — 提交任务、等待执行、补充信息、获取结果。
如何来理解它们之间的区别?
MCP Tasks:让一次 Tool 调用持续执行
MCP 的 Tool 接口围绕名称/描述、输入参数和返回结果展开。Tasks 在此基础上增加了任务 ID、状态查询、任务取消等接口约定。
整个交互仍围绕一次 Tool 的调用展开:无论执行多长时间,最终结果仍对应原来的工具调用。
工具背后当然可以是一个完全自主的 Agent。 它可以调用多个模型、运行工作流、自行检查结果等。但调用方只需要理解这个 Tool 对外提供的接口。
比如,把“订单分析 Agent”包装成 MCP Tool。尽管 Tasks 现在让这个 Tool 一次能够运行更长时间,但没有为它增加跨任务的上下文、交付物关联等更多约定。
A2A:把任务放进 Agent 的持续交流中
A2A 则面向 Agent之间的互操作。
调用方先通过 Agent Card(对方的“名片”) 了解对方提供什么能力和访问方法,再发送消息表达需求;对方可以直接回复消息,但更多时候创建一个需要持续跟踪的 Task。
A2A 的协作过程所涉及的核心对象要比一次 MCP Tool 调用复杂:
-
Message:消息。表达任务、补充条件,或传递一轮回复。
-
Task:用来跟踪一项具体工作的状态。
-
contextId:把相关消息和多个任务关联到同一上下文。
-
Artifact:表示交付成果,例如报告、文件或其他数据。
例如,销售助手 Agent 向订单分析 Agent 发起协作任务:
“分析上个月订单异常,给出处理建议。”
订单分析 Agent 交付报告后,用户又要求:
“针对华东地区的问题,补充客户跟进清单。”

A2A 可以在同一 contextId 下关联这次后续交流,引用前面的任务,再创建新的工作任务。
这种方式有助于连续协作。当然,Agent 具体如何保存自己的上下文、理解任务、完成任务,仍由自己实现。
两者对比
我们对两者做一个对比,帮助理解:
| 比较点 | MCP + tasks | A2A |
| 工作入口 | 调用工具 | 向Agent发送消息 |
| Task作用 | 工具调用中的持续执行 | 收到消息后建立的工作 |
| 补充消息 | 根据任务给出的要求,用tasks/update答复 | 根据关联任务和上下文消息继续交流(对话) |
| 最终成果 | 工具的调用结果 | Artifact对象带的交付物 |
| 多任务关联 | 工具本身无状态,自行设计任务关联方法 | 可以通过 ContextID 把多次任务关联 |
| 状态观察 | 通过tasks/get查询;或者订阅任务通知 | 支持任务状态、产物更新的流式事件;支持webhook推送机制 |
如果要做最简单的总结性对比就是:
MCP 的 Tasks 在协议与使用上更简洁,但复杂的协作需要自行实现;
A2A 天生为 Agent 互操作而设计,支持更复杂的多轮交互与协作机制。
另外,MCP 在集成上更简单,目前几乎所有的 Agent 都支持 MCP。
选择建议
在具体的使用场景上,我们的建议是:
-
如果已有 MCP 接入,且需求可以表达为明确的工具(能力/输入/输出)时,优先考虑 MCP+Tasks。
比如生成某报告、数据校对、长时间的统计分析等。这种任务的职责、输入和输出的边界很清晰,也无需复杂的反复交互(即使后台运行了复杂 Agent)。
-
如果需要把独立 Agent 提供给其他系统(特别是外部系统)使用,并持续协作、且交付物复杂,可考虑 A2A。
例如采购 Agent 与供应商 Agent 多轮协商交期、替代方案和报价,并关联到多次任务及交付物。此时采用 A2A,可以减少大量接口协商工作(消息、上下文、交付物等)的工作量。
总的来说,在有了 MCP 的 Tasks 后,针对复杂长任务 Agent 的集成,的确又多了一种可选且便捷的方式。
MCP Tasks 与 A2A 的“合作”
同一套系统也可以同时使用两者。
对外通过 A2A 接收目标、交流条件、交付成果;Agent 内部通过 MCP 调用 CRM、库存、文档等能力,其中耗时工具再使用 Tasks:

在这个例子中,销售助手与订单分析 Agent 的任务协作;与订单分析 Agent 借助 MCP+Tasks 来调用 CRM 系统的服务并不冲突。
![]()
以上是我们认为新版 MCP 规范中最值得关注的变化:用无状态请求简化部署、MRTR 完成多轮补充输入、以 Tasks 扩展支持持续运行的后端任务。
这些调整更贴近企业级 Agent 系统的实际需要:连接分散系统、复用业务能力、减少重复集成,以及执行长时间的复杂任务等。
此外,官方近期发布的 Roadmap 还计划进一步完善任务交互、渐进式工具发现等能力。
可以看到,MCP 一直在吸收社区建议,并围绕真实应用需求持续改进。随着企业 Agent 系统的落地加快,相信 MCP 仍将发挥重要作用,成为企业 Agent 系统中不可或缺的重要连接层。
191

被折叠的 条评论
为什么被折叠?



