MCP resource read errors surface as 'Connection closed' instead of the actual JSON-RPC error

Resolved 💬 5 comments Opened Apr 17, 2026 by ensell-yes Closed May 30, 2026

Summary

When an MCP server returns a proper JSON-RPC error for a resource read (e.g. -32603 Unknown resource URI), Claude Code's MCP client reports this to the user as MCP error -32000: Connection closed — implying the connection died. The connection is fine; the server replied with an error. The real error message never reaches the user.

Reproduction

Against any MCP server that handles resources/read but doesn't implement a specific URI:

// Server-side handler:
if (!knownUris.includes(params.uri)) {
  return { jsonrpc: "2.0", id, error: { code: -32603,
    message: "Failed to read resource " + params.uri + ": Unknown resource URI: " + params.uri } };
}

From Claude Code, call ReadMcpResourceTool({server: "movp", uri: "movp://movp/manifest"}) where that URI isn't registered.

Expected: error surfaces something like MCP -32603: Unknown resource URI: movp://movp/manifest

Actual: MCP error -32000: Connection closed

The process is fine — subsequent reads on OTHER URIs in the same session succeed. I verified by spawning the server manually and sending both the unknown-URI request and a valid request back-to-back; the server returned a proper -32603 for the first and a proper result for the second without exiting.

Why this matters

This caused real debugging lost-time for us on MostViableProduct/movp-plugins: our /movp:doctor diagnostic tried to read an MCP resource, got "Connection closed," and we chased a server-crash hypothesis (kept the MCP server process alive across reads to see which call killed it, wrote crash-detection in our smoke harness, etc.) before realizing the server was healthy and Claude Code was just hiding the real error.

Suggested fix

For ReadMcpResourceTool (and the equivalent path for tool calls): if the MCP server returns a JSON-RPC error object, surface error.code and error.message directly instead of normalizing to -32000 Connection closed. Reserve -32000 for actual transport failures (child exited, stdio pipe closed).

Environment

  • Claude Code CLI (current release as of 2026-04-17)
  • Node 20 / macOS 26.1
  • MCP server using NDJSON stdio transport

Happy to provide a minimal-reproduction MCP server if helpful.

View original on GitHub ↗

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