先理解
刚接触这个知识点
补齐先备概念,读原理与反例,再用自己的话解释为什么。
从核心原理开始 →理解 → 实现 → 排错 → 取舍
考察 stdio、Streamable HTTP、会话恢复与业务幂等的区别。
知识内容核对 2026-10-03 · 原题来源核对 2026-10-02
建议先理解:
工具调用的结构、授权与业务契约 →幂等、未知结果与任务恢复 →按当前基础选择起点,也可以依次深入。遇到不熟悉的概念,先回到核心原理;完成后用知识练习检查理解。
LEARN · PRACTICE · REFLECT
先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。
核心知识 · 连接恢复、消息恢复与业务核验
先备概念:JSON-RPC 请求匹配、SSE 游标、业务幂等
传输断开表示消息通道中断,不表示业务动作取消或未发生。请求 ID 匹配响应,事件 ID 定位消息,业务操作 ID 去重副作用;三种身份不能互相替代。
网络连接有建立与断开,协议请求有发送与响应,业务动作有提交与生效。连接先断而动作后完成完全可能。若把连接状态当业务状态,新连接一建立就重发,会重复外部写操作。
固定 MCP 2025-11-25 修订中,服务器可提供 SSE 事件重放,客户端以 Last-Event-ID 请求续流;这是可选能力。会话失效时需要重新初始化,原会话 ID 不能无限继续用。取回迟到响应之后仍要按调用关联处理,而非把重复事件执行成第二个动作。
本地持久化操作 ID、参数摘要和未知状态。服务器支持幂等则复用同一业务键,没有消息恢复时仍可通过业务查询核验。HTTP 的重试或 SDK 自动重连不提供外部 exactly-once;stdio 的 stdout 则必须只承载协议,日志污染也会导致通信失败。
不能把断连等同于工具未执行。先区分传输恢复、协议会话恢复和业务操作核对:支持事件恢复时按游标取回消息,会话失效时重新初始化,外部写操作则凭业务操作 ID 查询回执。新连接或新的 JSON-RPC ID 都不自动保证幂等。重试条件取决于工具语义和下游幂等支持,而不只是 HTTP 状态。
JSON-RPC 请求 ID 用于匹配请求与响应,会话 ID 用于协议会话,业务 operation_id 用于识别一次逻辑动作。三者生命周期不同。客户端进程重启可能生成新协议 ID,但同一笔待核对操作应保留业务 ID。stdio 下还要防止日志写到 stdout 污染协议消息,日志应走独立通道。
先将本地操作标为结果未知,暂停同一业务动作的重复提交。若服务端提供流恢复能力,则从已确认事件游标恢复;会话被服务端终止时按协商流程建立新会话。恢复消息并不等于重新执行工具,客户端应去重已消费事件。若无法恢复响应,再通过业务查询工具或操作账本核对结果。
只读查询可按预算重试;写操作只有在下游支持相同幂等键,或已可靠确认未执行时才可重试。若既无幂等机制也无法查询,就进入人工核对或明确的未知状态,不能承诺恰好执行一次。TCP 连接关闭、浏览器退出和请求取消也不是同一个业务信号。
在服务端提交动作后、响应送达前主动断开连接,再连接并观察是否出现重复副作用。还要测试重复事件、游标过期、会话失效和进程重启。规范中的可选恢复能力需要检查实际服务端支持,不能把某个 SDK 的实现当成所有 MCP 服务都具有的能力。
沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 1 层Last-Event-ID 是业务幂等键吗?
不同标识解决不同问题,混用会把恢复误当成重执行保护。
不是。Last-Event-ID 告诉服务器客户端最后接收的流事件位置,用于可选消息恢复;业务幂等键识别同一逻辑操作,需要执行端支持去重。恢复同一事件或创建新会话不会自动避免重复付款。把事件消费记录与业务操作账本关联,分别管理消息去重与副作用去重。
沿着这个回答继续深入
第 2 层同一成功事件被重放两次,客户端怎么避免重复更新任务?
明确游标用途后,仍需处理客户端重复消费的故障窗口。
按服务器、会话或流范围和事件 ID 记录消费进度,更新业务状态时再按操作 ID 做幂等合并。能把进度与本地状态同事务提交时这样做;否则重启后可能再消费,合并仍应安全。事件内容绑定原 call_id,不能误配给新请求。
沿着这个回答继续深入
第 3 层事件已收到但进度没落库就崩溃,恢复应该从哪里开始?
消息收到与本地提交不原子,恢复正确性依赖安全重放。
从最后可靠保存的游标开始,允许重放已经看过的事件。业务状态应用保持幂等,宁可重复读取也不要跳过未知事件;若外部副作用由消费触发,还需独立操作键。无法原子保存时必须设计重放安全,不能以“收到过”当持久证据。
第 1 层服务器不支持恢复流怎么办?
可选恢复缺失时,业务核验必须独立存在。
不等待不存在的协议能力。建立或重新初始化合法连接后,先查业务操作状态;只读调用可有界重试,写调用按下游幂等支持和核验结果决定。既无法查询也不能去重的动作保留未知并人工核验,新 JSON-RPC ID 不能证明旧请求未执行。
第 1 层stdio 服务把日志打印到 stdout 会怎样?
传输可靠性与协议格式相连,通信错误仍不决定业务事实。
日志可能被当作 JSON-RPC 消息解析,造成解析错误或请求响应错配。协议输出写 stdout,诊断日志走 stderr 或独立日志文件,并防止依赖库把启动横幅写入 stdout。排查时区分协议解析失败与业务错误,不能因解析失败直接重做写动作。
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
改变的条件:断连换成客户端等待预算耗尽
延伸问题:业务处理可以当失败重做吗?
不能。等待超时与断连同样只说明本地未取到结果。查询原操作,按幂等策略继续;客户端停止等待不必等同取消远端。可取消工具需要明确取消请求及回执,已提交写入仍核验。
保持不变的原理:通信和等待状态不能替代业务结果。
改变的条件:重连可以续会话变成会话已失效
延伸问题:旧操作记录要随会话丢掉吗?
不丢。按协议建立新会话并重新发现能力,同时保存旧业务操作的查询依据。会话状态可能消失,但支付、发布等外部事实仍存在;新会话只提供新的通道。确认工具版本与权限后再处理原未知动作。
保持不变的原理:业务生命周期可能长于协议会话,操作账本必须独立。
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
画出提交已成功但响应丢失的时序,列出重连后的三个分支。