MCP 工具安全重试实战:用可靠性 Sidecar 模式杜绝重复工单
教程文档人工智能【免费下载链接】mcp-for-beginnersThis open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.项目地址https://gitcode.com/GitHub_Trending/mc/mcp-for-beginners点击查看免费下载可靠性问题在 MCPModel Context Protocol工具开发中极易被低估响应丢失并不等于操作未发生。本文以 mcp-for-beginners 仓库中的《Safe Retries for MCP Tools: A Reliability Sidecar Pattern》一课为核心结合 08-BestPractices/reliability-sidecars 下的 Python/SQLite 可运行示例与确定性测试系统讲解如何用可靠性 SidecarReliability Sidecar模式为 MCP 工具构建幂等、可恢复、可对账的重试机制。读完本文你将掌握 operation key 的设计、原子认领、状态机建模、先对账再重试的决策流程以及如何在本地复现响应丢失故障并验证不会产生重复工单。为什么超时意味着结果未知想象一个支持工单工具客户端调用create_support_ticket工具在票务系统中成功提交了工单T-0001但连接恰好在此刻断开客户端永远看不到响应。此时客户端唯一确定的事实是响应丢了它不知道工单是否存在。如果客户端盲目重试票务系统会再创建一张T-0002——这就是典型的重复副作用。下面的时序图展示了这一场景以及引入 operation key 后如何恢复关键洞察在于对同一预期动作复用同一个 operation key工具就能在重试时通过存储层找到原始认领、向票务系统发起对账查询最终返回已有的T-0001而不是创建T-0002。可靠性 Sidecar 是什么可靠性 Sidecar 是围绕工具维护恢复状态的应用程序代码它可以是一个库、中间件、带数据库支撑的服务也可以干脆是工具实现的一部分。它不一定要是独立进程也不是 MCP 协议层面的功能——它是应用层的设计模式。Sidecar 承担四项职责在调用外部系统之前保存预期动作intended action只允许一个 worker 认领该动作记住足够的状态以便崩溃后能够恢复当结果不确定时去检查外部系统。本课面向 MCP 规范2026-07-28。MCP 没有协议级的会话session概念因此 operation key 就是一个普通的工具参数由持久化的应用状态作为支撑同样的模式在更早的 MCP 版本上同样成立。四个标识符各司其职不可互换在构建可靠性机制时很容易把 JSON-RPC ID、MCP Task ID、operation key、工单 ID 混为一谈。它们有关联但解决的问题完全不同标识符标识什么能否跨重试存活JSON-RPC ID一次请求与响应否每次请求都要使用新的 IDMCP Task ID一个长期运行的任务是保留它用于轮询Operation key一个预期动作是对该动作重试时复用Ticket ID已保存的结果是对账确认后返回它进度通知progress notifications和 Trace 上下文有助于观测一次请求取消cancellation是请求工作停止。但它们都不能阻止重复工单的产生——只有围绕 operation key 的防护机制能做到这一点。构建防护从 operation key 到 MCP 工具 Schema在第一次调用工具之前就创建 operation key并把它与整个工作流一起保存。每一次创建同一张预期工单的尝试都使用同一个 key{ operation_key: op-login-ticket-0001, title: Cannot sign in }不同的预期工单必须获得新的 key。在生产环境中应生成不透明、不可猜测的值如 UUID/随机串而不要把客户数据直接拼进 key——否则会泄露信息并降低不可预测性。本课使用的完整 MCP 工具 schema 如下它同时约束了输入与输出{ name: create_support_ticket, title: Create support ticket, description: Creates or recovers one support ticket for an operation key., inputSchema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { operation_key: { type: string, minLength: 16, maxLength: 128, description: Stable key reused for the same intended action. }, title: { type: string, minLength: 1, maxLength: 200 } }, required: [operation_key, title], additionalProperties: false }, outputSchema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { ticket_id: { type: string }, operation_key: { type: string }, status: { type: string, const: verified } }, required: [ticket_id, operation_key, status], additionalProperties: false } }注意几点设计取舍operation_key的minLength为 16确保不会用短小、可猜测的值additionalProperties: false杜绝模型在输入中夹带多余字段输出 schema 用const: verified保证工具成功返回时一定携带经过验证的状态。在 reliability_sidecar.py 中工具以TOOL_ID create_support_ticket:v1标识自身——工具名与版本号是认领作用域的重要组成部分见下文。把认领绑定到调用者与输入哈希已认证调用者的身份来自服务器上下文server context而不是模型提供的工具输入。这一点至关重要caller_id这类敏感信息绝不能进入由模型控制的 MCP 输入 schema否则任何客户端都可以伪造他人身份。每一份存储的 operation 记录都应限定到该调用者、租户或服务账号工具名与版本对定义外部动作的规范化输入所做的哈希。输入哈希回答一个简单问题这次重试要的是同一张工单吗如果同一个 key 已被绑定到不同的 title就必须拒绝该调用——如果输入变了却返回早前的结果会掩盖契约错误。源码中对应实现见 reliability_sidecar.py_input_hash先把 payload 用sort_keysTrue的紧凑 JSON 序列化再做 SHA-256保证规范化后哈希稳定create_support_ticket 在认领后第一时间比对record[input_hash] ! input_hash不一致即抛出OperationKeyConflict。测试 test_same_key_with_different_input_is_rejected 验证了先用Cannot sign in建单成功再用同一 key 提交Cannot reset password会被拒绝工单数仍为 1。原子认领与状态机claimed → completed → verified认领记录必须通过单次原子数据库操作保存。原子意味着两个 worker 不可能同时看到空记录、又同时成为所有者。当另一个服务器实例可能接管重试时进程内锁是不够的。在 SQLite 实现中这一点由两处配合完成见 reliability_sidecar.pyBEGIN IMMEDIATE获取写锁阻止并发写入交错INSERT OR IGNORE配合主键(caller_id, tool_id, operation_key)见 建表语句保证同一作用域下只能插入一条记录cursor.rowcount 1即表示我是唯一的所有者。工作流在动作仍处于planned时创建 key随后示例持久化三种状态claimed一个 worker 已预订该操作completed票务系统已返回结果verified对票务系统的读取确认了该结果。崩溃可能让存储状态停留在claimed即使工单其实已经创建。因此必须把所有非终态nonterminal的 claimed 记录都视为不确定直到外部证据给出结论——绝不能假设claimed意味着什么都没发生。状态迁移在代码中被严格约束_mark_completed与_mark_verified都只允许从(claimed, completed)迁移见 reliability_sidecar.py并发测试 test_concurrent_claims_admit_one_owner_without_state_regression 用Barrier让两个线程同时抢认领断言认领结果恰好是[True, False]并验证迟到的 completed 更新不会把 verified 状态回退。先恢复再重试失败后的决策流程工具调用失败后在发出下一次外部写入之前先判断目前已知什么在调用票务 API 之前就失败的校验属于已知失败known failure可以用同一个 operation key 原样重试如果修正输入会改变预期工单则要为这个新动作创建新 key。如果请求可能已经到达票务系统先对账reconcile再重试。对账指把保存的认领记录与权威的工单记录做比较恰好找到一条匹配记录时返回已有工单只有当工单被确凿地证明不存在、且下游契约允许再试一次时才发起重试。未找到并不总是确凿的采用最终一致性搜索的提供方可能需要有限等待后再查一次。如果系统无法搜索、给出矛盾结果、或无法安全地为下一次尝试去重就停下并上报outcome unknown。这种拒绝猜测的做法有时被称为 failing closed故障时关闭。对应实现中对账逻辑位于 create_support_ticket先调用ticket_service.find_by_operation_key见 TicketService多条匹配会抛ReconciliationConflict找到即校验标题一致并标记verified找不到且认领非新建时按状态抛ReconciliationConflictcompleted 却无外部工单或OperationInProgress已有认领但无终态外部证据绝不盲目重复写。证据、Tasks 扩展与取消工具响应说明工具报告了什么存储的检查点checkpoint说明工作流记录了什么。最强的证据来自拥有结果的系统本身——对本例而言就是从票务系统读回恰好一条匹配工单。要把证据与风险匹配低风险的通知场景提供方的消息 ID 也许就够而支付、部署、破坏性操作可能需要提供方状态、账本或人工复核作为证据。MCP Tasks 扩展是对该模式的补充适用于长期运行的工作。Task ID 让客户端在断连后恢复轮询但它不识别、也不去重工单本身。使用 Tasks 时标识符的链接关系为operation key - Task ID - ticket ID - verification evidence取消是协作式的不是回滚取消被确认后工单仍可能已创建因此不确定的结果依然需要对账。故障注入演练在本地运行 Python 示例示例只用标准库和 SQLite可在本地直接运行。它使用两个 SQLite 文件一个代表操作存储operation store另一个代表外部票务系统不存在横跨两个文件的事务。故障被精确注入在工单已提交、但 sidecar 尚未写入 completed 检查点之间——这正是最危险的窗口期见 reliability_sidecar.pyinject_response_lossTrue时抛出ResponseLost。Python 直连方法接受caller_id作为已认证服务器上下文的替身。切勿把caller_id加进由模型控制的 MCP 输入 schema——它只存在于服务端内部调用链中。运行测试前可以先预测结果路径重试后的结果工单数量盲目重试naive丢失T-0001的响应后创建T-00022受防护重试sidecar找到并返回T-00011执行命令cd 08-BestPractices/reliability-sidecars/python python -m unittest discover -p test_*.py -v六个确定性测试见 test_reliability_sidecar.py分别验证盲目重试会制造重复test_naive_retry_repeats_a_committed_effect 中naive_create_support_ticket无任何防护见 reliability_sidecar.py重试后得到T-0002工单数为 2响应丢失 重启能凭持久认领恢复一张工单test_guarded_retry_reconciles_after_response_loss 先用inject_response_lossTrue触发故障此时存储状态为claimed随后用新的对象模拟重启的 worker无任何进程内记忆重试后返回T-0001、状态verified、工单数为 1已验证的重试直接复用缓存结果test_verified_retry_returns_cached_result 两次调用返回完全相同的结果工单数保持 1变更输入或冲突的外部证据会被拒绝见上文提到的 test_same_key_with_different_input_is_rejectedOperationKeyConflict与ReconciliationConflict各司其职已有认领但无外部证据时安全停止test_existing_claim_without_evidence_does_not_repeat_effect 直接预置claimed认领重试抛OperationInProgress随后写入completed却找不到外部工单则抛ReconciliationConflict工单数始终为 0并发认领只允许一个所有者且不回退已验证状态test_concurrent_claims_admit_one_owner_without_state_regression双线程抢认领结果为[True, False]验证迟到的completed写入不会覆盖verified。本课的英文原版文档位于 08-BestPractices/reliability-sidecars/README.md核心实现为 reliability_sidecar.py确定性测试为 test_reliability_sidecar.py建议对照阅读。示例有意省略了过期认领的租约lease机制。生产环境的所有权接管策略需要有限期的租约、原子化的所有权转移以及执行前再做一次外部检查。生产环境检查清单在第一次外部尝试之前创建并保存 operation key把 key 绑定到调用者、工具版本和规范化输入哈希拒绝在已有 key 下提交变更后的输入用共享存储上的原子操作只允许一个所有者当下游提供方支持幂等性时把 key 转发给它在另一次写入之前先对账不确定的结果在整个重试窗口内保留已验证结果与证据当外部结果无法安全确认时停下来人工审查。参考资料MCP 规范2026-07-28模型上下文协议官方规范MCP2026-07-28服务端工具指南MCP Tasks 扩展长期任务与轮询JSON-RPC 2.0 规范请求/响应 ID 语义文中还提到的可选社区实现Agent Enhancer Utilities是对该应用层模式的一种实现其 planner 负责选择恢复方案checkpoint 记录认领与不确定结果状态而真正的动作仍由领域工具或 MCP 服务器执行与验证。它不属于 MCP 规范的一部分本课也不要求使用它且需要注意checkpoint 状态永远不能当作工单存在性的外部证据。赞分享教程文档人工智能【免费下载链接】mcp-for-beginnersThis open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.项目地址https://gitcode.com/GitHub_Trending/mc/mcp-for-beginners点击查看免费下载相关推荐MCP 工具安全重试实战可靠性 Sidecar 模式——用稳定操作键与对账消除重复副作用MCP 工具安全重试实战可靠性 Sidecar 模式——用稳定操作键与对账消除重复副作用 导读 MCP 工具的调用方在超时后盲目重试可能把已经成功提交但响教程文档人工智能MCP 开发最佳实践实战指南从工具设计、测试策略到可靠重试的 Sidecar 模式MCP 开发最佳实践实战指南从工具设计、测试策略到可靠重试的 Sidecar 模式 导读 本文以 mcp for beginners 开源课程中的 08 Be教程文档人工智能高效自动化指南5步实现星穹铁道模拟宇宙智能助手高效自动化指南5步实现星穹铁道模拟宇宙智能助手 Auto_Simulated_Universe是一款专为《崩坏星穹铁道》设计的模拟宇宙自动化工具通过先进的创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

环形导轨循环线±0.05mm定位精度:从公差分配到现场验收的全解析

环形导轨循环线±0.05mm定位精度:从公差分配到现场验收的全解析

做这类项目久了,你会习惯客户在需求表里写下“环形导轨循环线定位精度:0.05mm”。外行人觉得这数字没什么,内行人一看就头疼——“0.05mm”放在钻攻中心或者丝杆滑台上,顶多算个普通水准;但放在环形导轨上,…

2026/10/9 11:23:16 阅读更多 →
Kubernetes集群——Ingress篇

Kubernetes集群——Ingress篇

目录 一.认识Ingress——控制器 1.1Ingress介绍 1.2Ingress Controller介绍 二.Ingress-nginx 2.1简单介绍 2.2部署Ingress-nginx 2.3修改Ingress-nginx的Service类型 三.基于DaemonetHostnetwork部署Ingress-nginx(可选) 四.基于虚拟机名称访问…

2026/10/9 9:54:28 阅读更多 →
容器里堆只用 60% 却被 OOMKilled:JVM 少算的内存去哪了

容器里堆只用 60% 却被 OOMKilled:JVM 少算的内存去哪了

本文摘要:堆只用六成就被杀掉,缺口来自元数据、线程栈与直接内存这些非堆项。用NMT把内存拆成八个类别逐项归因,再按总账给各类显式设上限。该路径限JDK17容器环境,NMT常开多占内存,内存贴着限额的服务须谨慎。 一、问…

2026/10/9 10:51:24 阅读更多 →

最新新闻

基于COCA语料库的20200高频词表:英语词汇学习优先级指南

基于COCA语料库的20200高频词表:英语词汇学习优先级指南

1. 这份20200词表到底解决了什么问题做英文写作或者备考的人,大概都经历过这样的场景:打开一份所谓的高频词表,发现里面混着大量已经很少用的书面语,或者干脆是从某本老教材里扒下来的词汇,背了半天,真正在…

2026/10/9 11:45:49 阅读更多 →
风力叶片缺陷检测数据集与YOLOv8实战指南

风力叶片缺陷检测数据集与YOLOv8实战指南

简介:本资源是面向人工智能视觉算法工程师、工业缺陷检测研究者及高校相关方向研究生的风力叶片表面缺陷检测专用数据集,聚焦新能源装备运维中的自动化质检需求。数据集共5113张高质量图像,配套2000份PASCAL VOC格式XML标注文件,完…

2026/10/9 11:45:49 阅读更多 →
蓝桥杯既约分数题解:从暴力枚举到欧拉函数线性筛优化

蓝桥杯既约分数题解:从暴力枚举到欧拉函数线性筛优化

1. 从一道填空题看"既约分数"的暴力枚举边界蓝桥杯2020年初赛有一道填空题,题目编号1509,问的是在1到2020的范围内,有多少对互质的整数(i, j),也就是分子分母最大公约数为1的分数有多少个。这道题看起来简单到令人发指—…

2026/10/9 11:45:49 阅读更多 →
沪深全量日线数据管道搭建:从采集入库到复权因子避坑指南

沪深全量日线数据管道搭建:从采集入库到复权因子避坑指南

简介:沪深两市所有股票自上市以来至2022年1月10日的完整日线行情,在这份资源中一次汇集,覆盖市场全貌,主要面向量化研究者、技术分析爱好者及金融数据从业者,可用于历史复盘、规律挖掘与策略开发。数据字段十分完整&am…

2026/10/9 11:45:49 阅读更多 →
网盘直链解析新手指南:8 大网盘直链获取与第三方下载完整教程

网盘直链解析新手指南:8 大网盘直链获取与第三方下载完整教程

网盘直链解析新手指南:8 大网盘直链获取与第三方下载完整教程 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘…

2026/10/9 11:45:49 阅读更多 →
X光掌骨分割数据集实战:从数据可视化到训练避坑

X光掌骨分割数据集实战:从数据可视化到训练避坑

简介:这份资源面向医学影像处理与深度学习入门者,提供X光手掌骨骼的2分类分割数据集,可用于训练掌骨区域提取模型,适合图像分割课程实验、算法验证及小规模医学影像项目练手。包内共2000个文件,以1486个png掩膜、512个…

2026/10/9 11:44:47 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →