Skip to content

Tool error handling does not follow spec #159

@TrevorHinesley

Description

@TrevorHinesley

Describe the bug
According to the docs (and the relevant portion of the MCP spec), tool execution errors should look like the following:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Failed to fetch weather data: API rate limit exceeded"
      }
    ],
    "isError": true
  }
}

But instead, they look like the following (i.e., protocol error format):

{
  "jsonrpc": "2.0",
  "id": 4,
  "error": {
    "code": -32603,
    "message": "Internal error",
    "data": "Internal error calling tool fetch_weather_data"
  }
}

So the actual behavior of the MCP gem stack is:

  1. Tool raises an exception (e.g., ActiveRecord::RecordNotFound)
  2. MCP Server's call_tool catches it and re-raises as RequestHandlerError
  3. Seemingly, it is caught and re-raised here and somewhere JsonRpcHandler catches that and returns a JSON-RPC error response (had a bit of trouble finding exactly where the caught error lands).

Unless I'm missing something, this means the MCP gem documentation is incorrect - it does not automatically convert exceptions to isError: true responses. Instead, raising exceptions get converted to JSON-RPC protocol errors (code -32603).

Returning Tool::Response.new(content, error: true) would work as documented, but requires manual exception handling as a workaround.

To Reproduce
Steps to reproduce the behavior:

  1. Raise an error inside a tool call.
  2. Verify that response matches what the MCP spec deems a protocol error rather than a tool execution error.

Expected behavior
I expect for raised errors within tool calls (e.g., ActiveRecord::RecordNotFound) that are not deemed internal server errors to be handled intuitively, as tool call execution errors, rather than protocol (-32603) errors. This is what the README says should be the current default behavior for raised errors within tool calls.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions