Codex.MCP.Client.call_tool/4 currently defaults to three retries for every tools/call failure. That can replay a non-idempotent mutation when the server completed the write but the response was lost.
Current path:
request/4 sends tools/call.
- The destination commits a write.
- The response times out or the transport closes.
retry_or_error/8 invokes the same tool again because mcp_default_retries() is 3.
This is an ambiguous-success boundary, not a confirmed failure. Backoff does not make the replay safe.
Proposed minimal change:
- Make automatic
tools/call retries opt-in rather than the default, or require a caller-provided retry-safety predicate.
- Keep explicit retries available for read-only or provider-idempotent tools.
- Document that transport errors after request transmission may mean the external effect is uncertain.
- Add a deterministic regression fixture whose first call commits a synthetic mutation and drops the response; the default path must leave the mutation count at one.
A later enhancement could use MCP readOnlyHint / idempotentHint as advisory input, but unknown or missing annotations should remain conservative. These hints cannot provide exactly-once behavior by themselves.
Reference contract and fixture semantics: https://github.com/artiehinz/Agent-Enhancer-Utilities/blob/main/docs/RELIABILITY_SIDECAR_CONTRACT_V1.md
I can prepare the focused patch and test if this direction matches the project's compatibility policy.
Codex.MCP.Client.call_tool/4currently defaults to three retries for everytools/callfailure. That can replay a non-idempotent mutation when the server completed the write but the response was lost.Current path:
request/4sendstools/call.retry_or_error/8invokes the same tool again becausemcp_default_retries()is3.This is an ambiguous-success boundary, not a confirmed failure. Backoff does not make the replay safe.
Proposed minimal change:
tools/callretries opt-in rather than the default, or require a caller-provided retry-safety predicate.A later enhancement could use MCP
readOnlyHint/idempotentHintas advisory input, but unknown or missing annotations should remain conservative. These hints cannot provide exactly-once behavior by themselves.Reference contract and fixture semantics: https://github.com/artiehinz/Agent-Enhancer-Utilities/blob/main/docs/RELIABILITY_SIDECAR_CONTRACT_V1.md
I can prepare the focused patch and test if this direction matches the project's compatibility policy.