Skip to content

[mcp] bridge retries a failed tools/call after reconnect with identical params — at-least-once execution for non-idempotent tools (forget succeeds, then the host is told "not found") #103

Description

@devinmlowe

Evidence

src/interfaces/mcp/bridge.ts:228-247 (forward):

try {
  return await op(client);
} catch (err) {
  if (err instanceof McpError) throw new McpError(err.code, bareMessage(err), err.data);
  try {
    const again = await reconnect(`${what} failed: ${errMsg(err)}`);
    const result = await op(again);          // same req.params (bridge.ts:250)

Why it's a bug

A transport failure after the daemon has committed the call but before the response reaches the bridge (the documented trigger: engram update restarting the daemon) re-issues the identical tools/call. remember/remember_batch are mostly absorbed by consolidation dedup and ingest_turn is an upsert, but a retried forget memory_id performs the delete and then surfaces the second attempt's "memory not found" error to the host, and a retried commitments_update / remember with a superseded/conflict outcome can differ on the second run. There is no request id or idempotency key on the daemon side. Narrow window, so P3.

Suggested direction

Retry only tools/list / ping and calls whose failure happened before the request was sent (e.g. ECONNREFUSED on connect), or forward an idempotency key the daemon dedups for a short window; otherwise return the transport error to the host and let it decide.

Related: #58, #60.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority: P3Later: consistency, hardening, design work with no observed failures

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions