DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

MCP 进度回调报错

MCP 进程内工具被客户端进度回调异常拖垮,核对 Python SDK 2.3.0 的隔离修复,保留取消、超时和通知路径的区别。

MCP 工具本来能返回结果,加上客户端的 progress_callback 后,却在 await context.report_progress(...) 附近失败,客户端看到 UnexpectedToolError: Error executing tool。如果使用的是同一进程内的 Client(server),先看进度回调自己的异常。

Python SDK 2.1.1 有这个具体反馈:回调抛出 RuntimeError,异常沿直接调用路径传回服务器,让正常的工具也被标成失败。已核对的正式版 2.3.0 隔离了这类普通回调异常。

进度显示也在这次调用里

进程内客户端可以直接调用服务端处理函数,没有经过 stdio 或 HTTP 的 JSON-RPC 消息边界。旧 DirectDispatcher 等待客户端进度回调时,没有把回调异常与工具执行分开。

因此,显示进度的界面更新、日志适配器或回调断言一旦抛错,report_progress 就可能把它重新抛进工具函数。错误最终写着工具名,并不表示业务处理函数里的计算就是失败原因。

应保存完整异常链,核对连接是否确实由 Client(server) 建立、是否使用非 legacy 模式,以及回调里是否有对应异常。同一工具走 HTTP 或 stdio 正常、进程内连接失败,也符合这类旧边界差异。

不能把所有 UnexpectedToolError 都按进度问题处理。工具自身异常、输入验证和结果转换失败,仍应沿自己的异常链检查。

2.3.0 的普通异常会记录后继续

正式修复在直接分发路径捕获进度回调抛出的 Exception,以 progress callback raised 记录,再让工具继续执行并返回正常结果。它没有取消工具的进度通知,也没有改变业务工具的输入和输出。

旧部署应选择包含此修复、且与应用接口兼容的版本。暂时保留旧环境时,可检查进度回调,把不影响业务结果的展示失败妥善记录;不能在最外层吞掉整个工具调用异常,再伪造一份成功结果。

日志本身也要保留边界,避免把工具参数、认证信息或其他敏感上下文直接写出。如果进度回调实际承载了必须成功的业务写入,则应重新划分责任,不能因为 SDK 隔离了异常就认为那份业务工作完成了。

取消与超时仍然有效

这项修复只捕获普通异常,不吞掉调用方取消或请求超时。一个一直阻塞的回调仍可能使请求到期;用户取消任务时,也不应为了隐藏进度日志继续运行工具。

修复也没有统一改变 DirectDispatcher.notify()。手工连接 dispatcher 对并自行提供通知处理器的应用,需要单独核对通知异常;普通 ClientSession 与服务端已有自己的通知回调隔离层,不能把问题中的两条路径说成都已由同一补丁修好。

测试中还有一个变化:过去在进度回调里 assert,可能让工具调用整体失败;修复后它会被记录,工具却可以正常返回。若测试需要验证进度内容,应保存实际收到的通知,在调用完成后另外断言,不能只依赖回调抛错作为失败信号。

验收时在获准的测试环境中分别确认:普通进度回调失败有日志、正常工具仍返回预期结果,工具自身失败仍被报告,超时与取消仍能结束请求。只有“不再看到 UnexpectedToolError”,不足以证明回调与业务结果都正确。