KEY TAKEAWAYS
- Legacy recovery can use GET with Last-Event-ID to resume the earlier stream; replay is optional. Modern recovery cannot resume that stream, and its changelog requires a new request with a new request ID.[1][2][3]
- Modern SSE closure MUST be treated as cancellation, but stopping work is a SHOULD. Cancellation does not establish rollback of an external effect.[2][5]
- Our proposed operating rule: separate transport recovery from permission to repeat a consequential write. Resolve the prior effect or establish an applicable duplicate-prevention contract before automatic reexecution.
Recovering a response and repeating a tool are different actions
Suppose an agent calls a booking tool and loses the HTTP response before learning the result. Reconnecting to retrieve the earlier response seeks messages about work already requested. Sending another tools/call submits a new request that may create another booking. The choice matters even when both actions are called a retry. This scenario is hypothetical, not an observed booking-service incident.
Model Context Protocol (MCP) describes two different HTTP recovery paths in the documents compared here. The 2025-11-25 transport permits resumable server-sent events (SSE), a stream of server messages. The 2026-07-28 binding removes Last-Event-ID resumption; its changelog says clients MUST re-issue a lost in-flight request as a new request with a new request ID.[1][2][3] Neither path, by itself, establishes exactly-once external effects.
The transport overview separates how messages are delivered from what they mean.[4] Recovering an answer therefore does not, by itself, establish permission to create a second booking. The comparison here is between recovering an earlier stream and submitting another tool request.
What changes across the two HTTP contracts
MUST, SHOULD and MAY below preserve the documents' requirement levels; they are not interchangeable guarantees. The new-request/new-ID MUST comes specifically from the 2026-07-28 changelog, while the binding supplies the no-resumption and SSE-cancellation rules.[2][3]
| Recovery question | 2025-11-25 | 2026-07-28 |
|---|---|---|
| Can the old SSE stream resume? | Event IDs are optional. A client wishing to resume SHOULD GET with Last-Event-ID; the server MAY replay after that cursor on the original stream and MUST NOT replay another stream's messages.[1] | Last-Event-ID resumption is not supported. The changelog says a broken response stream loses the in-flight request: clients MUST re-issue with a new request and new request ID.[2][3] |
| Does SSE disconnection cancel the request? | Disconnection SHOULD NOT be interpreted as cancellation. To cancel, the client SHOULD explicitly send a CancelledNotification.[1] | Closing the request's SSE response stream MUST be treated as cancellation. The server SHOULD stop work as soon as practical and MUST NOT send further messages for it.[2] |
| What happens to protocol sessions? | A server MAY issue MCP-Session-Id at initialization. If issued, the client MUST include it on subsequent HTTP requests. A 404 for that session means the client MUST send a new InitializeRequest without the session ID.[1] | Protocol sessions and the Mcp-Session-Id mechanism are removed; version and capabilities travel in per-request _meta instead of initialize.[2][3] |
| Can older GET/session recovery be assumed? | GET plus Last-Event-ID is the specified resumption route, even when the original stream began with POST. Availability of replay remains optional.[1] | Modern-only servers SHOULD return 405 for old GET/DELETE traffic and ignore old session/event headers. A dual-era server can separately serve negotiated legacy semantics.[2][6] |
The cancellation row applies to the request's SSE response stream; it does not establish an identical disconnect rule for a single-JSON response. Modern HTTP cancellation uses stream closure, while notifications/cancelled is the stdio mechanism.[5] The cancellation signal does not prove that execution stopped or that an accepted external effect was reversed.
A cursor, session and RPC ID are not a mutation key
- Event cursor: a legacy SSE event ID locates a position in a particular stream. If present, IDs MUST be unique across streams within the session, or the client when sessions are not used. Last-Event-ID asks for messages after that position; it does not identify a booking for duplicate prevention.[1]
- Protocol session: MCP-Session-Id groups legacy interactions. Reinitializing after a session 404 repairs protocol state; it does not establish that a preceding write never ran.[1]
- RPC correlation: a remote procedure call (RPC) request ID connects a request to its response. Modern IDs MUST NOT match another request still awaiting a response; a result response carries the corresponding ID. A new ID distinguishes the new RPC, not necessarily a new business intention.[9]
- Application mutation identity: our proposed operation record identifies the authorized business action, target and arguments. A provider may separately implement a duplicate-prevention key, but that key needs an explicit contract; none of the stream/session/RPC passages establishes one.
Legacy resumption is mechanically different from resubmission: GET with the cursor requests the earlier stream; it does not send another original tools/call. The server SHOULD prime an SSE stream with an event ID and empty data. Before server-initiated connection closure it SHOULD supply a retry field, and the client MUST respect that delay.[1] These provisions support reconnection without keeping every connection open indefinitely. They do not establish durable event storage, a universal retention period or restart survival.
Modern recovery sends another POST carrying a new RPC request; it cannot recover the earlier response by its event cursor.[2][3] Reopening subscriptions/listen creates another notification subscription, not replay of a lost tool response.[8] Request-scoped streams make the cancellation signal explicit, but leave the application to establish whether another tool execution is safe.
A proposed decision procedure for response loss
This procedure is our proposed application-level operating practice, not additional MCP normative text. The changelog still says clients MUST reissue a lost in-flight request with a new request ID.[3] Before an automatic retry reexecutes a consequential write, we recommend checking the prior effect or the applicable duplicate-prevention contract. That check is a safety prerequisite, not a protocol exception; reconciliation alone does not satisfy the reissue requirement.
- 1. Identify the protocol era before choosing recovery. Modern requests carry version and capabilities in _meta; initialize selects legacy semantics on a dual-era server. A recognized modern version error calls for supported-version selection or request correction, not automatic legacy fallback.[2][6] Test compatibility with a non-mutating discovery request or probe, rather than a consequential write.
- 2. Before a consequential call, retain its authorized intent, target, arguments, RPC ID and any documented provider operation key. Treat an application key and a transport request ID as separate identities.
- 3. On response loss, record 'result not observed', not 'operation failed'. For a supported legacy resumable stream, use its cursor-based GET path and supplied retry delay. If resumption is unavailable or unsuccessful, do not silently replace it with another mutating POST.[1]
- 4. For a known non-mutating read, check that access and request rate/cost remain permitted and that fresh data is acceptable. Under the modern recovery rule, reissue with a new RPC ID. Treat the answer as a new observation, not the recovered bytes or snapshot of the lost response.[3]
- 5. For a consequential write, use an authorized, documented provider/application lookup to reconcile the original operation. Require correlation to the exact target and arguments. A missing, delayed, inaccessible or ambiguous record is not proof of nonexecution; hold automatic repeat while the outcome is unresolved.
- 6. Repeat only when the applicable evidence supports it: a definitive no-effect outcome under the documented status contract, or a duplicate-prevention contract covering this operation and retry interval. If reissuing, change the RPC ID as required; retain a provider key only where its contract requires that. Record the evidence and decision, not a transport-derived exactly-once claim.
The cost of this separation is extra application state, lookup work and potentially delayed completion. A low-consequence read may not justify that overhead. For a booking, payment or message, however, a second accepted effect can matter more than immediate response recovery. MCP's transport documents do not provide the implementation-specific outcome evidence needed to settle that trade-off.
Worked decisions: a lost inventory read and a lost booking result
Hypothetical completed examples, not experiments: all IDs and observations below are fictional and unexecuted. Assume the 2026-07-28 HTTP binding and an implementation contract confirming that the inventory tool is non-mutating, rather than relying on a metadata label. Also assume the booking provider documents an authorized lookup by application operation identity. That lookup is provider-specific evidence in this example, not a standard MCP operation-status endpoint.
| Case | Assumed evidence | Completed decision |
|---|---|---|
| Inventory lookup: read-101 | Its SSE response was lost. Continued access and request rate/cost are permitted; fresh inventory is acceptable. | Reissue the read as read-102, with a new RPC ID. Treat the answer as a fresh observation, not resumed read-101 bytes. |
| Create booking: write-201 | Before sending, the client saved booking-intent-17 and the authorized target/arguments. After response loss, the documented lookup returns an accepted booking correlated to that exact intention and payload. | Do not create a second booking. Record the prior accepted effect and reconcile the missing result through the provider contract. This application outcome is not transport reissue or proof of protocol conformance. |
| Same booking, unresolved lookup | The lookup is inaccessible, delayed or cannot uniquely correlate the booking with booking-intent-17. | Hold automatic repeat and keep the outcome unresolved pending reconciliation. An empty lookup result or missing response does not prove that the first booking was never accepted. |
If this hypothetical provider instead documented atomic duplicate handling for booking-intent-17, the business key could remain stable while a reissued RPC changes from write-201 to write-202. That would rely on the provider's identity, payload and retention rules—not on a new JSON-RPC ID, cancellation or stream replay. We established no such provider contract in this research.
What would change the repeat-write recommendation
A server-specific contract can be stronger than the transport baseline. Seek evidence that a duplicate key is scoped to the correct account and operation, bound to the intended payload, handled atomically under concurrent retries, retained throughout the recovery window and propagated to the external provider when needed. A gateway that suppresses duplicate messages without controlling the downstream mutation is not enough.
A documented authoritative status service could also settle the decision: an accepted-effect record would support reconciliation without another create; a definitive no-effect result could support an authorized repeat. Its consistency, access and retention limits matter. Separately authorized loss/concurrency/restart tests could test these claims, but none were run here. A product's specific evidence might therefore justify automatic reissue where our baseline guidance holds it unresolved.
Method and revision limits
We compared the actual version-bound transport text and supporting changelog, cancellation, versioning, patterns and core ID rules from one MCP publisher family. This establishes a documentary comparison, not independent empirical corroboration, SDK compatibility, rollout, reliability or business impact. No live tool write or recovery behavior was observed.
The observed edition index labels 2026-07-28 as latest.[7] Its changelog also retains the phrase 'introduced in this draft' in an error-code change.[3] We preserve both observations rather than independently declaring the edition released or draft. Publication/update dates, implementation deployment dates and the site's full deployed source commit were not established. Preserved hashes identify the bytes retrieved on 10 October 2026 KST, not original July bytes.
The comparison uses preserved primary-document passages recovered through ordinary public HTML retrieval, not search snippets or incomplete heading-only extracts. Existing MCP Tasks coverage already notes cancellation and reconciliation limits. This article adds the cursor-based GET versus new-POST mechanism, the four identity roles and completed read/write decisions; it does not offer a new task-lifecycle contract.
Sources & scope
Documentary comparison checked 10 October 2026 KST: MCP 2025-11-25 transport and the observed 2026-07-28 HTTP binding, changelog and supporting core documents. No SDK, server or interruption experiment was run. Examples are hypothetical and unexecuted; edition labels are not launch dates. The article date identifies this prepared edition, not production activation.
- MCP 2025-11-25: Transports ↗
Official primary text retrieved 10 October 2026 KST; optional replay, session and reconnect rules. Publication/update and rollout dates unknown.
- MCP 2026-07-28: Streamable HTTP ↗
Official primary text retrieved 10 October 2026 KST; request-scoped HTTP, no resumption and SSE cancellation. No implementation test.
- MCP 2026-07-28: Key Changes ↗
Official primary text retrieved 10 October 2026 KST; exact new-request/new-ID MUST. Retains draft wording elsewhere; edition label is not a launch date.
- MCP 2026-07-28: Transport Overview ↗
Official primary text retrieved 10 October 2026 KST; binding versus message semantics. Publication/update date unknown.
- MCP 2026-07-28: Cancellation ↗
Official primary text retrieved 10 October 2026 KST; transport-specific cancellation and timing limits. Requested utilities route redirected to this patterns URL.
- MCP 2026-07-28: Versioning and Compatibility ↗
Official primary text retrieved 10 October 2026 KST; legacy, modern and dual-era semantics. No adoption or rollout finding.
- MCP 2026-07-28: Specification Index ↗
Official page retrieved 10 October 2026 KST; used only for observed latest label, not a release-status or implementation guarantee.
- MCP 2026-07-28: Message Patterns ↗
Official primary text retrieved 10 October 2026 KST; notification subscription is request-scoped. No all-event replay finding.
- MCP 2026-07-28: Core Overview ↗
Official primary text retrieved 10 October 2026 KST; RPC ID uniqueness and response correlation, not business deduplication.
Publication history
- — Initial prepared edition: documentary transport comparison, proposed operating procedure and hypothetical completed read/write decisions. Edited for clarity; actual activation requires separate release evidence.
Have a correction or a different perspective? Contact Palanthos.