Reusing a receipt is useful when communication becomes uncertain. But what should happen if the same request ID carries different content? Northstar binds an ID to the serialized validated request and rejects a changed pair rather than treating it as another execution.

An ID is a label, while content is a separate contract

Returning an old result solely by ID could make a caller believe changed content succeeded even though it never ran. Executing changed content under that ID would instead surprise a caller relying on duplicate prevention. Both interpretations undermine the meaning of the request ID.

The server retains a fingerprint made by JSON-serializing the validated request. A different fingerprint under an existing ID raises MCP_REQUEST_ID_REUSED. This is not an AI judgment about natural-language equivalence. It mechanically fixes the conditions under which a request may reuse a receipt.

Store the pending promise as well as the eventual result

The receipt map stores both fingerprint and reply promise. Even before the first execution finishes, another connection with the same ID and content waits on that promise. Absence of a completed result does not start a second execute callback.

If a socket disappears after execution starts, the promise's work can remain in the host. Reading the same receipt later continues toward that outcome. This is not an exactly-once guarantee covering a remote service, but it is a concrete mechanism preventing duplicate callbacks for one request in this process.

Do not evict old mutation receipts to make room

The receipt store has a limit. When it is full, it rejects a new ID rather than discarding an old mutation receipt. If an evicted ID returned, the server could treat it as new and repeat an input whose result had been uncertain.

Between bounded memory and replay protection, I chose an explicit failure at the limit. An operator must inspect current work and results before recovery. Automatically restarting the process to erase the receipts cannot be described as continuation of the same guarantee.

Request receipts and work journals have different lifetimes

This map retains receipts for the server process lifetime. It does not protect an ID forever across browser restarts. Plugin run IDs, durable work records and actual page storage results require checks at their own layers.

Retaining a request ID also does not decide that two articles with equal title and body are the same business job. The same content under a new ID can be another request. Item fingerprints and completed-result reuse belong to a work journal. Transport deduplication and business deduplication are separate responsibilities.

An error can be the retained result of that request

An execute error becomes an ok:false result retained by the same promise. Resending its ID does not silently restart the failed execution. Corrected input needs a deliberate new request and inspection of the current state.

The integration test sends the same context request twice under one ID and checks that execute ran once. Sending a tools request under that ID must be rejected without another callback. I compared the implementation with those tests rather than creating duplicate live manuscripts or reservations as an experiment.

Separate correction from rereading a result

A caller should distinguish these intentions too. Rereading the same request retains both ID and content. Executing changed content requires inspecting the earlier outcome and user scope before constructing another request. Continually changing IDs merely to suppress errors defeats the protection at the caller level.

Business delivery APIs need to specify which input an ID denotes, its retention lifetime and what must be inspected after restart. I treat a receipt as a record of execution responsibility rather than only a convenience cache. Rejecting the moment one number becomes another command preserves that boundary.