The tool call timed out. Did the write happen?
An error response does not prove that nothing happened.
The previous note showed how a successful query can return incomplete evidence. A tool timeout poses the opposite problem: the caller gets an error after the thing it asked for has already happened.
One write, two perspectives
In a local experiment, a scripted caller invoked a Model Context Protocol (MCP) tool over stdio. The tool sent an HTTP write to a fake provider on loopback. The provider recorded an in-memory receipt, then waited half a second before answering. The tool waited only 150 milliseconds for a response.
The tool returned an MCP error. The caller recorded a failed span with error.type = timeout. Neither the error nor the span contained the receipt. No model, credentials or external service took part.
Synthetic local experiment · November 3, 2026 · Scripted decisions
One write, three retry decisions
- CallerSend writeOne logical operation ID.
- ProviderCommit receiptCommit time not measured.
- ToolRead times out150 ms HTTP read timeout.
- CallerReceive MCP errorCaller spans: about 165–210 ms.
- ProviderAttempt reply500 ms configured delay after commit.
Sequence, not a time scale. The provider committed before its delay; the caller span includes more than the HTTP read.
01 Retry without checking
- Caller observed
- Two MCP errors. No receipt in hand.
- Harness knew
- Two commits for one logical operation.
02 Look up the operation ID
- Caller observed
- HTTP 200: found a committed receipt. Reused it without a second write.
- Harness knew
- One commit.
03 Lookup unavailable
- Caller observed
- HTTP 503: no receipt. Held the retry; write outcome unknown.
- Harness knew
- One commit, not visible to the caller.
Keep three claims separate
- The run finished. The orchestrator reached the end of its work.
- The tool reported an error. The caller did not receive a successful response.
- The write happened. A destination record confirms the effect for that operation ID.
The unavailable lookup is the most useful case. The write happened, but the caller had no way to establish that. Its honest report was: tool timed out; write outcome unknown; retry safety not established.
What made it into the telemetry?
In a local test of PackDB’s operation extractor, one captured timeout span retained its error status and error type. That was evidence of a failed tool call, not a failed write. The committed receipt in the second case came from the provider lookup, not from PackDB.
A companion check deliberately recorded a genuine MCP error as a successful span. The extractor then reported a successful operation and the tested query pack counted zero errors. A query over that span alone cannot recover a distinction the producer never recorded.
What this does not establish
PackDB did not prevent the duplicate, decide whether to retry or diagnose the destination outcome. The callers followed scripts. The experiment did not measure human decision quality or time saved.
Looking up a receipt and then writing is not an idempotency guarantee. Concurrent callers or a stale lookup can still race. Here the caller reused a positively observed receipt; an empty lookup would not establish that another write was safe. The test did not demonstrate automatic destination-outcome ingestion or detection of missing call hops.
Before retrying
Identify the record that could confirm the effect: a transaction row, a delivery receipt or a provider operation ID. If that record is unavailable, keep the tool error and the unknown write outcome separate in the investigation.
Trace a tool retry locally in Python or TypeScript. A read-only lookup hits a synthetic timeout on its first attempt and succeeds on its second. The agent reports success, but its trace still shows the failed attempt. No account or API key is needed. The lookup writes nothing, so this example does not reproduce the write-and-receipt experiment above.
When a tool call fails in your system, what record tells you whether the action it attempted already happened?