MCP notifications/progress 怎么接:progressToken、递增进度与超时收口
来源:17golang原创
时间:2026-08-16 22:12:22 241浏览 收藏
批量索引、长文档解析这类 MCP 工具如果只在最后返回一次结果,客户端很难判断它是在正常运行、卡住,还是已经失联。notifications/progress 提供了一条轻量的反馈通道:客户端在原始请求的 _meta 中放入 progressToken,服务端再用同一个 token 回传当前进度。
进度通知不是心跳,也不能替代最终结果。它必须和正在运行的活动请求绑定,进度值需要持续递增;工具执行完成、失败、超时或被取消后,客户端要停止等待后续通知,回收本次请求的所有状态数据。
progressToken要在原始请求生成,并且在对应活动请求结束前保持全局唯一。notifications/progress至少携带 token 和当前 progress 字段,总量未知时 total 可以省略。- progress 每次上报都必须向前推进,不能用同一个数值反复刷屏来假装状态更新。
- 客户端必须兼容完全不发进度通知的服务端实现,用完成、错误、超时和取消四个场景统一做收尾处理。
先把用户看到的等待状态拆开
一个名为 build_search_index 的工具需要扫描 120 个文件。客户端发起 tools/call 后,服务端可能需要几十秒才能返回最终结果。此时界面至少要区分三种状态:请求已成功发出、任务仍在后台处理、任务已经走完全部流程。进度通知只负责中间那段“仍在处理”的可见反馈,不能用来证明网络连接一定健康。
这个区分非常实用。网络层还在传输数据,不代表业务逻辑一定在向前走;反过来,服务端也有可能因为任务执行太快,连一条进度通知都来不及发就直接返回结果。客户端如果把“没收到进度通知”直接判定成失败,会把正常的快速响应和本身不支持进度上报的服务都误判成故障。

请求里的 token 决定通知归属
客户端需要获取进度时,把 token 放在请求参数的 _meta 里。token 可以是字符串或整数类型,但在所有正在运行的活动请求中必须唯一。服务端发通知时原样带回这个 token,客户端才能把收到的进度通知绑定到正确的进度条上。
{
"jsonrpc": "2.0",
"id": 17,
"method": "tools/call",
"params": {
"name": "build_search_index",
"arguments": {"root": "/workspace/docs"},
"_meta": {"progressToken": "index-17"}
}
}
服务端不要凭空生成一个没有对应来源请求的 token,也不要把上一次请求的 token 缓存在全局变量里。并发调用场景下最容易出现的问题,就是A请求的进度被错误推到B请求的界面上。工程上可以把 token、请求 id、任务句柄和过期时间存在同一条活动记录里,任务执行完之后立刻删掉这条记录。
通知字段怎么设计才不会误导
最小粒度的进度通知包含 progressToken 和 progress;如果任务总量已知,再额外带上 total。下面的48表示已经完成的文件数,100表示总文件数:
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "index-17",
"progress": 48,
"total": 100,
"message": "正在处理第 48 个文件"
}
}
| 字段 | 用途 | 客户端处理逻辑 |
|---|---|---|
| progressToken | 关联原始请求 | 找不到对应活动记录时直接丢弃通知,同时记录诊断日志 |
| progress | 当前进度值 | 只接受比上次记录更大的数值 |
| total | 已知任务总量 | 字段缺失时直接显示已处理数量,或者用不确定进度条展示 |
| message | 人类可读提示文案 | 展示短状态给用户看,不把它作为机器判断任务状态的依据 |
如果任务总量未知,不要为了显示百分比随便填一个猜测的数值。可以只显示“已处理 48 项”,或者用不确定进度条。message 适合给用户解释当前执行阶段,不能替代结构化的状态字段;客户端不要通过解析“正在处理”这类文案来判断任务是否完成。
递增、限频和停止是三个硬检查规则
绑定同一个活动 token 的 progress 应该持续增加,就算 total 数值不知道也要遵守这个规则。客户端可以记录上次收到的进度数值,遇到回退或者重复值时保留旧状态,同时记录异常日志。服务端则应该按处理批次或者时间窗口发送通知,不要每扫描一行文件就发一条进度,避免通知本身占用过多传输和渲染资源。
- 递增:
12 → 28 → 48是符合预期的正常更新;48 → 48不能被当作新的进展。 - 限频:按批次、时间窗口或者百分比变化发送通知,具体频率由服务端自行决定。
- 停止:最终结果、错误或取消确认发出之后,不能继续给同一个活动 token 发进度通知。

完成、失败、超时和取消分别收口
客户端可以把一次调用建模为 active、completed、failed、timed_out 和 cancelled 五种状态。收到最终结果时进入 completed;收到协议错误或者服务端返回的错误时进入 failed。触发本地超时逻辑后进入 timed_out,此时要停止更新界面,不能因为后续迟到的通知又把进度条重新点亮。
如果用户主动终止请求,还要按照 MCP 的取消机制发送 notifications/cancelled,同时带上原始请求 id。服务端收到之后要尽快终止对应的后台任务;客户端不能只隐藏掉进度条,却放任后端任务继续无限制运行。取消通知和进度通知是两条完全独立的消息:前者是向服务端传递停止执行的意图,后者只负责上报当前处理进度。
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": 17,
"reason": "用户停止索引"
}
}
一个可直接落地的客户端检查顺序
- 创建本地请求记录,生成当前活动范围内唯一的
progressToken。 - 发送
tools/call,把生成好的 token 放进_meta。 - 只接收仍处于
active状态的 token 对应的通知,同时检查 progress 数值是否符合递增规则。 - total 字段存在时计算完成百分比;字段不存在时直接使用不确定进度条或者数量提示。
- 最终结果、错误、超时和取消任一事件触发后,标记当前请求为终态,删除本地存储的活动 token。
- 后续收到的迟到通知只记录诊断信息,不要恢复已经结束的界面状态。
这个执行顺序把“展示进度反馈”和“判定任务最终结果”完全分开了。就算某个服务端从来都不发进度通知,只要最终响应在超时窗口内正常返回,整个调用流程仍然可以正常走完。
常见问题
服务端必须发送 progress 通知吗?
不需要。规范允许服务端不发送通知、按自己的节奏发送通知,或者省略 total 字段。客户端必须把进度通知当作可选的体验增强项来处理。
progress 可以从 0 重新开始吗?
同一个活动 token 对应的进度不应该回退。如果实际工作需要拆成多个阶段执行,应该让 progress 继续向前累加,或者为新的独立请求生成全新的 token。
没有 total 时能不能显示百分比?
没法可靠显示。更合理的做法是展示已处理数量、不确定进度条或者当前阶段提示,避免用猜测的总量生成虚假的完成率。
最终结果到了以后还收到通知怎么办?
直接判定当前请求已经结束,忽略这条迟到的通知并记录调试日志。服务端要修正活动 token 的生命周期管理逻辑,保证任务完成后立刻停止发送进度。
把进度条当作反馈,而不是承诺
MCP 进度通知最实用的价值,是让长任务的等待过程变得可感知可理解;它并没有把普通网络连接变成高可靠的任务队列。只要坚持用 token 绑定请求、进度数值递增、通知限频和终态收口这几个原则,客户端就能在有通知时给用户提供细致的等待反馈,就算没有通知也能保证整体流程正常运行。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
363 收藏
-
340 收藏
-
320 收藏
-
426 收藏
-
407 收藏
-
科技周边 · 人工智能 | 8小时前 | 安全 · mcp · ai agent · MCP ToolAnnotations readOnlyHint destructiveHint idempotentHint195 收藏
-
452 收藏
-
312 收藏
-
433 收藏
-
科技周边 · 人工智能 | 11小时前 | go · 人工智能 · Gemini API · 函数调用 · 多轮对话 · Go 函数调用 工具链 Gemini 3 thoughtSignature Interactions API202 收藏
-
科技周边 · 人工智能 | 12小时前 | openai · Responses API · AI应用开发 · OpenAI Responses API 上下文压缩 compaction conversation state428 收藏
-
217 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习