MCP Idempotency演示(流式HTTP、Python)
此仓库包含一个最小的演示,说明MCP工具调用中的幂等性,使用 python,the MCP Python SDK,以及 流式HTTP 运输。
注: 首选方法是引入一个新的顶级属性 idempotencyKey 到CallToolRequest。这使得幂等性明确且是必需的,而不仅仅是一段可选或可忽略的元数据。通过制造 idempotencyKey 作为一级属性,客户端和服务器都清楚幂等性是协议的核心部分,可以减少歧义和意外遗漏的风险。但是,此演示在 _meta 现场(_meta.io.modelcontextprotocol/idempotency-key)以避免破坏当前的MCP规范。两种形式见下文。
组件
server_non_idempotent.py:带工具的MCP服务器:
- make_payment(IBAN, BIC, amountMinorUnits, currency) – _不_ 幂等性;重试时,它会再次收费。 - get_balance() –退货 { "balanceMinorUnits": }. - get_transactions() –退货 { "transactions": [...] }.
server_idempotent.py:工具相同,但make_payment用途_meta.io.modelcontextprotocol/idempotency-key是
幂等性。使用相同密钥重试 不 申请付款 再一次。
client.py:一个客户:
1. 呼叫 get_balance. 1. 呼叫 make_payment 一次(服务器速度较慢,因此HTTP客户端超时)。 1. 重试 make_payment 同样的论点。 1. 呼叫 get_balance 和 get_transactions 再次打印结果。
客户端对非幂等服务器运行此序列一次,对 幂等服务器,因此您可以直接比较结果。
创建venv
uv venv安装依赖项
uv install -r requirements.txt运行服务器(流式HTTP)
在一个终端中:
uv run server_non_idempotent.py在另一个终端中:
uv run server_idempotent.py两台服务器都公开了MCP 流式HTTP 接受JSON POST请求的端点。此演示使用保留密钥方法实现兼容性:
{
"tool": "make_payment",
"params": {
"IBAN": "...",
"BIC": "...",
"minorUnits": 2500,
"currency": "EUR"
},
"_meta": {
"io.modelcontextprotocol/idempotency-key": "73c2eaf4-8cc4-4ba4-908f-7017f0aa2f4f"
}
}首选(未来)方法:
{
"tool": "make_payment",
"params": {
"IBAN": "...",
"BIC": "...",
"minorUnits": 2500,
"currency": "EUR"
},
"idempotencyKey": "73c2eaf4-8cc4-4ba4-908f-7017f0aa2f4f"
}运行演示客户端
两台服务器都在运行时:
uv run client.py您应该注意:
- 非幂等服务器
- 第一 make_payment 调用:客户端记录超时,但服务器已经应用了付款。 - 第二 make_payment 调用:服务器应用支付 _再次_ (无幂等性),因此 get_balance 显示两个借记和 get_transactions 包含两个匹配的付款。
- 临时服务器
- 第一 make_payment 调用:客户端超时,但服务器应用一次支付并存储 这 _meta.io.modelcontextprotocol/idempotency-key. - 第二 make_payment 用同样的电话 _meta.io.modelcontextprotocol/idempotency-key:服务器 不 再次申请付款,因此 get_balance 仅显示一笔借记 get_transactions 只有一笔付款。
这提供了一个具体的、端到端的说明,说明为什么幂等性对于安全重试支付等工具很有价值。虽然此演示在中使用了保留密钥 _meta 为了兼容性,建议的方法是 idempotencyKey MCP规范中的一级属性。
