SEP-3182: Request Idempotency - #3182
Conversation
Add Initial SEP Draft for - Request Idempotency
- seps/0000-request-idempotency.md -> seps/3182-request-idempotency.md - seps/0000-request-idempotency-faq.md -> seps/3182-request-idempotency-faq.md - Update SEP-0000 header and PR field to SEP-3182
- Capability negotiation now via server/discover, not initialize (removed by SEP-2575) - Add "Relationship to the 2026-07-28 stateless core and MRTR" section - Fix outdated initialize reference in Scope section
|
The new stateless/MRTR section draws a useful distinction between continuing an MRTR exchange and retrying a request. I think one lost-response case still falls between those definitions. SEP-2322 makes the initial and continuation A compact conformance sequence would be:
That does not reuse one key across the MRTR exchange; it scopes a key to each independent round. I would either include The linked reference implementation has a separate wire-level mismatch: |
|
Thanks for the detailed review, both observations are helpful. On MRTR, I think you've identified a genuine ambiguity rather than a disagreement. My intent was exactly what you describe: the initial request and each continuation are independent The gap, as you point out, is that if this SEP is taken to apply to MRTR continuation requests, the current equivalence rule doesn't account for On the reference implementation, that's also a fair observation. The current prototype was written to demonstrate the behavioral semantics—the duplicate-execution failure mode and the proposed deduplication/conflict behavior—rather than the final protocol integration. It predates the draft settling on a dedicated Thanks again for taking the time to dig into the details—this is exactly the kind of review that helps tighten both the specification and the prototype. |
Matches the corresponding SEP edit: MRTR continuation requests are out of scope for this SEP rather than left ambiguous. No other FAQ answers affected.
Reviewer noted that if this SEP's equivalence rule (tool name + arguments) were applied to an MRTR continuation, it would ignore inputResponses/requestState even though those can change the operation's outcome. Rather than partially extend equivalence without implementation experience, the SEP now states the exclusion explicitly. No other section changes; equivalence, retention, capability, and conflict semantics are unaffected.
|
Pushed the fixes for both points: MRTR: explicitly scoped MRTR continuation requests out of this SEP, rather than leaving it ambiguous whether the existing equivalence rule applied to them. inputResponses/requestState aren't accounted for in equivalence today, and I'd rather say so directly than partially extend the mechanism without implementation experience behind it. Happy to revisit if there's a concrete case for covering it now. Thanks again for the close read — both were real gaps, not just wording. |
|
Happy to change the proposal to use a reserved _meta key instead if reviewers feel that's a better fit for MCP's extension model. My preference is still a dedicated field because the guarantee this SEP is trying to standardize depends on the value surviving end-to-end, and today multiple SDKs/frameworks have been observed dropping _meta (as discussed in the SEP/FAQ). If the WG believes _meta is the right long-term home and is comfortable making preservation a normative requirement, I'm happy to update the proposal accordingly. |
Summary
Adds an optional
idempotencyKeyfield totools/call, letting a client mark a request as a possible retry of one the server may already have processed, and a server return the original result instead of re-executing a side effect. Introduces a correspondingtools.idempotencycapability for negotiation.Motivation and Context
MCP has no way for a server to distinguish "this request never arrived" from "this request arrived, executed, and the response was lost" — so a client retrying after a dropped connection or timeout has no safe way to do so for a side-effecting tool call. This is an acknowledged gap, not a new observation: SEP-1686 (Tasks) explicitly deferred a general idempotency mechanism to "a dedicated proposal" rather than solving it narrowly for Tasks. In the absence of one, independent implementations are already reinventing incompatible ad hoc conventions to work around it (cited in the Motivation section of the SEP). This proposal is that dedicated mechanism, scoped deliberately narrowly: one optional field, one new capability, explicit conflict semantics for the hardest edge case (a reused key with different arguments).
How Has This Been Tested?
A reference implementation (linked below) demonstrates the mechanism end to end against a real MCP client/server exchange over stdio:
idempotencyKey: the same retry is deduplicated and returns the original result without re-executing.Reference implementation: abluva/mcp-request-idempotency-reference
Breaking Changes
None. The field and capability are both opt-in and additive — servers and clients that don't implement this proposal are unaffected, and existing
tools/callrequests withoutidempotencyKeybehave exactly as they do today.Types of changes
Checklist
Additional context
A companion FAQ, included in this PR, addresses anticipated objections (why not _meta, why not an HTTP header, why tools/call only) and is explicit about genuine open tradeoffs not yet resolved (capability granularity, interaction with cancellation and batch requests).