NEXUM-004 on a real spec: how a public MCP storefront closed an IdempotencyMissing finding in a day

This is not a demo spec. Fabian Williams (@fabianwilliams) built a public, MCP-callable storefront — a real purchase flow, live on fabswill.com. When Nexum's rules were walked against his spec by hand, one of them failed: NEXUM-004. Here's what happened, in his own words and his own pull request.

The spec

Fabian's storefront serves one MCP-callable endpoint that produces an identical, protocol-neutral audit-trail receipt regardless of caller — he tested it against both hosted Claude Desktop and a fully-local Qwen3.6 27B running offline on his laptop, same six runtime checks, same result. He posted it as a thread on X on May 16, 2026.

Mehdi replied the next day: the runtime checks looked solid, but what did the spec look like before it reached the client? The receipt-URL pattern — one endpoint satisfying both the security audit and the finance billing view — was interesting from a blast-radius angle: an endpoint that serves two consumers is also one endpoint an agent can call for both.

Fabian took the offer. The Nexum scanner binary wasn't public yet, so he walked his purchase_free_bundle spec against the manifest's five enumerated rules by hand. Four passed or didn't apply. One failed.

The finding — NEXUM-004 IdempotencyMissing

HIGH purchase_free_bundle is a mutating MCP tool: it mints a receipt, upserts a contact in Brevo, mints a JOSE-signed download token, and dispatches a fulfillment email. The tool's inputSchema exposed no Idempotency-Key. Any agent that retries on timeout — the default retry behavior in most LLM-SDK client policies — would double-issue the bundle and double-fire the email.

Why the runtime guards didn't catch it

Fabian's storefront already had runtime governance in place: a 5-requests-per-hour rate limit per IP, and a $5/day cost ceiling. Neither one fires on this bug. Two retries inside the same hour both land comfortably under the rate-limit cap on first try. A duplicate free-bundle issue costs nowhere near the daily ceiling. As Fabian put it, that's exactly the defense-in-depth gap Nexum's framing predicts: runtime guards and static spec review catch different classes of failure. A spec-level check on the schema itself catches what request-volume and cost-based guards structurally cannot see.

The fix — PR #1

Fabian shipped the fix the same day, merged May 17, 2026:

  • Schema. Added idempotency_key (optional, 8–128 chars, pattern [A-Za-z0-9._-]) to the MCP tool's inputSchema, with the tool description updated to recommend it for production agents.
  • HTTP header. Both /api/a2a/mcp and /api/a2a/purchase also accept a standard Idempotency-Key request header — the tool argument wins if both are present.
  • Storage. A new idempotency.ts module backed by Azure Table Storage. PartitionKey and RowKey are hashed values — no raw key or email is stored.
  • Replay semantics, Stripe-style. On every request with a valid key, the table is checked before input validation runs. On a hit, the original receipt is loaded from Blob storage and returned exactly as-is.
  • Only successes are cached. Failure receipts are never stored, so a transient downstream failure (a Brevo blip, for example) doesn't get poisoned by a cached error — the agent's retry re-runs the flow as intended.
  • Fail open. A missing cache hit or a failed write are both swallowed rather than surfaced as errors. Idempotency is a safety belt here, not a new failure mode.

Known v1 limitations

Fabian documented these in the PR itself, rather than glossing over them:

  • Concurrent requests with the same key can both miss the cache and both run the flow — last-write-wins on the table, and two receipts get written to Blob. A Stripe-style in-progress lock (set state to processing under optimistic concurrency, return 409 on collision) is the planned v2 hardening.
  • No table TTL yet — mappings live until manually reaped. Negligible cost at demo volume; flagged for revisit past 10k+ rows.

Why this matters

Runtime guards — rate limits, cost ceilings — govern behavior: how often and how much. They say nothing about whether a single call, executed exactly once as designed, is safe to retry. A static read of the spec catches that class of risk before the first agent ever calls the tool — defense-in-depth on top of runtime governance, not a replacement for it. That's the whole premise behind the Nexum Cert.

Is your MCP server agent-safe?

Upload your OpenAPI spec and get a Nexum Cert + PDF report in seconds. Free. No account required.

Scan your API free → View the registry