READ · UNDERSTAND · TRANSFER
阅读理解,按需巩固
先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。
核心知识 · 连接恢复、消息恢复与业务核验
先理解核心原理
先备概念: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 服务都具有的能力。
工程推演
- 场景
- 面试假设:MCP 发布工具已完成发布,但响应流在网络抖动中丢失。
- 设计决策
- 保留 operation_id,先恢复消息或查询发布回执。
- 验证目标
- 重连不产生第二次发布,无法核对时保持未知状态。
- 适用边界
- 没有下游幂等或查询接口时无法仅靠 MCP 承诺 exactly-once。
连续追问与解答
沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 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。排查时区分协议解析失败与业务错误,不能因解析失败直接重做写动作。
举一反三:条件变了,怎样推导?
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
连接未断但请求超时
改变的条件:断连换成客户端等待预算耗尽
延伸问题:业务处理可以当失败重做吗?
推导与参考解答
不能。等待超时与断连同样只说明本地未取到结果。查询原操作,按幂等策略继续;客户端停止等待不必等同取消远端。可取消工具需要明确取消请求及回执,已提交写入仍核验。
保持不变的原理:通信和等待状态不能替代业务结果。
会话被服务器终止
改变的条件:重连可以续会话变成会话已失效
延伸问题:旧操作记录要随会话丢掉吗?
推导与参考解答
不丢。按协议建立新会话并重新发现能力,同时保存旧业务操作的查询依据。会话状态可能消失,但支付、发布等外部事实仍存在;新会话只提供新的通道。确认工具版本与权限后再处理原未知动作。
保持不变的原理:业务生命周期可能长于协议会话,操作账本必须独立。
易错点
- 断线就无条件重发
- 把 JSON-RPC ID 当业务幂等键
- 把关闭连接当取消动作
参考资料
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
检查自己理解到哪一步
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
- 基础达标
- 知道断连可能发生在动作已提交之后。
- 中高级信号
- 能拆解流恢复、会话重建与回执核对。
- 资深信号
- 用故障注入验证重复事件和无法核对的保守终态。
巩固练习 按需完成 · 建议 15 分钟
画出提交已成功但响应丢失的时序,列出重连后的三个分支。
展开验收要求与检查点
- 已成功动作不被盲目重复
- 无法核对时返回未知
- 事件去重与业务幂等分开
重点检查
- 区分请求、会话、业务 ID
- 处理断连后的未知结果
- 不把可选恢复能力当强保证