Skip to main content
Glama
abluva

mcp-request-idempotency-reference

by abluva

Request Idempotency — Reference Implementation

Minimal, runnable demonstration of the protocol-level mechanism proposed in SEP-3182: Request Idempotency: an idempotencyKey field on tools/call params (a sibling of arguments, not nested inside it), with deduplication performed in server-side dispatch before any tool handler runs, and explicit conflict semantics for a reused key presented with different arguments.

This is a demonstration server, not a production implementation — the dedup store is an in-memory dict with no eviction. It exists to make the before/after failure mode concrete for reviewers, per the SEP process's prototype requirement ("a standalone proof-of-concept demonstrating the key mechanics").

Setup

pip install -r requirements.txt

Note on the version pin: this demo uses FastMCP from mcp.server.fastmcp, and relies on CallToolRequestParams allowing extra fields (model_config = {"extra": "allow"}) to carry idempotencyKey as a sibling of arguments. As of the mcp SDK's 2.0.0 release, both of these changed: FastMCP was renamed and moved to MCPServer in mcp.server.mcpserver, and CallToolRequestParams no longer allows extra fields — an idempotencyKey sent under 2.0.0 is silently dropped at construction, with no error, rather than causing an import failure. Installing a plain pip install mcp today will pull 2.0.0 and this demo will appear to run while never actually deduplicating anything. The pin above (mcp>=1.9.0,<2.0.0) avoids both problems. Porting this demo to 2.0.0 would require idempotencyKey to be added as a declared field (or an equivalent extension mechanism, if MCPServer provides one) rather than relying on extra-field passthrough — that port is out of scope for this prototype.

Related MCP server: acel-toy-server

Run

python3 client_demo.py

This spawns server.py as a stdio subprocess and runs three scenarios:

  1. No idempotency support — a lost-response retry double-charges.

  2. With idempotencyKey — the same retry is deduplicated; the cached result is returned, no re-execution.

  3. Conflict semantics — the same key reused with different arguments is rejected outright, not replayed or silently executed.

Verified working end-to-end against mcp==1.9.4 on 2026-08-01.

Note on the 2026-07-28 stateless spec: this demo's dedup logic (_dedup_store in server.py) is keyed entirely by the client-supplied idempotencyKey and never depends on protocol-level session state, so nothing here needed to change when MCP went stateless. The one thing worth calling out for anyone adapting this into a real server: in a horizontally-scaled, stateless deployment, that store needs to be shared across instances (a cache or database), not a per-process dict like this demo uses — see the SEP's "Relationship to the 2026-07-28 stateless core and MRTR" section for why.

Files

  • server.py — the guarded (charge_guarded) and unguarded (charge_unguarded) tool implementations, plus a reset_ledger test helper.

  • client_demo.py — drives all three scenarios against server.py.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Demonstrates MCP 2026-07-28 behavior for long-running tool calls, task lifecycle (get, update, cancel), and elicitation clarification during async tasks.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Demo MCP server for ACEL, a runtime verification middleware that blocks a rule-violating tool call before it executes. 5 tools (authenticate, read/validate/delete records, send payment) showing ACEL enforcing call ordering and state preconditions live via the official MCP SDK's middleware hook.
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Demonstrates stateful application patterns on the stateless MCP 2026-07-28 protocol, enabling request-scoped state, multi round-trip confirmations, and streaming progress updates across independent tool calls.
    -
  • F
    license
    A
    quality
    A
    maintenance
    Exactly-once execution for irreversible agent actions: an agent claims the right to run an effect, and a retry after a lost response returns the sealed result instead of charging again. 12 tools over stdio, including a gateway mode where the agent holds a single-use ticket and never the provider key.
    9
    17 PyPI
    -