[BUG] MCP tool errors not surfaced to model in autonomous mode — silent data loss

Resolved 💬 4 comments Opened Mar 12, 2026 by stackbilt-admin Closed Apr 10, 2026

Problem

When an MCP tool returns isError: true in its response, Claude Code in autonomous mode (claude -p) does not treat this as a blocking failure. The model sees the error text but continues as if the operation succeeded. In autonomous sessions without a human to catch this, it leads to silent data loss.

Reproduction

  1. Connect an MCP server with a tool that can fail (e.g., a memory/state store)
  2. Run claude -p "Store this fact: 'test data'" --dangerously-skip-permissions
  3. If the MCP tool's backend is down, it returns { isError: true, content: [{ type: "text", text: "Error: store failed" }] }
  4. The model sees the error text but may proceed to report success to the user/orchestrator
  5. Subsequent reads return nothing — the data was never persisted

Real-world impact

We operate a production memory system via MCP. Our MCP handler was wrapping a backend write in try/catch and returning a success-looking response even on failure:

// Before fix — MCP tool swallowed the error
try {
  await backend.store(data);
  return { content: [{ text: `Recorded: "${data}"` }] };
} catch (err) {
  console.error(err); // logged but not surfaced
  return { content: [{ text: `Recorded: "${data}"` }] }; // still "succeeded"
}

This is partly our bug (we fixed it to return isError: true), but the deeper issue is: even when the MCP tool correctly returns isError: true, autonomous Claude Code sessions don't halt or retry. The model acknowledges the error in its reasoning but may still tell the orchestrator "done" — because there's no mechanism to force a retry or mark the task as failed based on MCP tool errors.

Expected behavior

In autonomous mode, MCP tool errors should be treated with the same severity as a failed Bash command:

  1. The model should explicitly acknowledge the failure in its output
  2. If the failed tool was critical to the task, the model should retry or report failure — not silently continue
  3. The --output-format json termination metadata should include MCP tool errors in an errors array
  4. Orchestrators should be able to detect "task completed but had MCP errors" vs "task completed cleanly"

Suggested approach

  • Track MCP isError responses during the session
  • Include them in JSON output metadata: "mcp_errors": [{ "tool": "memory_store", "error": "..." }]
  • Optionally: add a --strict-mcp-errors flag that treats any MCP isError as a blocking failure (similar to set -e in bash)

Environment

  • Claude Code: latest (v2.1.74)
  • MCP transport: Streamable HTTP
  • Mode: claude -p with --dangerously-skip-permissions

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗