Why idempotency matters even more in MCP

In a normal HTTP integration you control the retry. In an agent integration, the agent may decide to retry on its own — or two parallel agent runs may both try to create the same customer. Idempotency keys are how you stop that from turning into duplicates.

How it works

EPD’s idempotency mechanism is identical to the REST API: the same 24-hour window, the same conflict semantics, the same error codes. The only difference is how you pass the key.

REST

POST /v1/orders
X-EPD-Idempotency-Key: 8e2c1b9a-4f3d-...

MCP

Every write tool accepts an optional idempotency_key argument:

{
  "name": "create_order",
  "arguments": {
    "customer_id": "550e8400-e29b-41d4-a716-446655440000",
    "payment_method_id": "6ba7b815-9dad-11d1-80b4-00c04fd430c8",
    "items": [
      { "product_id": "6ba7b810-9dad-11d1-80b4-00c04fd430d1", "quantity": 1 }
    ],
    "idempotency_key": "8e2c1b9a-4f3d-..."
  }
}

If you don’t pass one, the MCP server generates a key from the call’s content. This dedupes accidental retries from the same session — but it cannot dedupe across sessions or across agents. Pass an explicit key whenever a retry from a different process is possible.

When to pass an explicit key

Onboarding flows

A user submits a “sign up + first charge” form. Generate an idempotency key once on submit, pass it through to the MCP tool. If your worker crashes and restarts, the same key arrives — no duplicate charge.

Bulk operations

Importing 10,000 customers? Per-row idempotency keys make the whole job restartable from where it failed.

Parallel agents

If two agent runs may try the same action, share an idempotency key derived from the underlying intent (e.g. an order id from your system).

Composite tools

create_customer_and_charge is one logical action — pass one key. EPD propagates it to the inner steps.

Errors

Error codeMeaning
idempotency_key_in_useA previous call with this key is still running. Retry after a short delay.
idempotency_key_conflictSame key, different arguments. Use a fresh key for the new intent.
invalid_idempotency_keyKey is empty, too long, or has illegal characters.

Read tools and idempotency

Read-only tools (get_*, list_*) are naturally idempotent and do not require a key. The annotation idempotentHint: true confirms the tool is safe to retry.