zeroclaw-labs/zeroclaw · error · anyhow::Error

MCP tool `{tool_name}` error {}: {}

Error message

MCP tool `{tool_name}` error {}: {}

What it means

call_tool received a JSON-RPC response whose top-level error object is set — a protocol-level failure (unknown tool, invalid params, server internal error), as opposed to isError:true, which signals tool-execution failure. The message embeds the JSON-RPC error code and the server's message text.

Source

Thrown at crates/zeroclaw-tools/src/mcp_client.rs:745

            let inner = self.inner.lock().await;
            inner
                .config
                .tool_timeout_secs
                .unwrap_or(DEFAULT_TOOL_TIMEOUT_SECS)
                .min(MAX_TOOL_TIMEOUT_SECS)
        };
        let operation = format!("tool call `{tool_name}`");
        let resp = self
            .dispatch_rpc(
                "tools/call",
                json!({ "name": tool_name, "arguments": arguments }),
                tool_timeout,
                &operation,
            )
            .await?;

        if let Some(err) = resp.error {
            bail!("MCP tool `{tool_name}` error {}: {}", err.code, err.message);
        }

        let result = resp.result.unwrap_or(serde_json::Value::Null);

        // MCP servers signal *tool-execution* failures (as opposed to JSON-RPC
        // protocol errors) with HTTP 200 + `result.isError: true` and the detail
        // in `result.content[].text`, per the MCP spec. Surface it (scrubbed and
        // length-bounded) so the failure is visible to the model and the log.
        let server_name = self.inner.lock().await.config.name.clone();
        check_result_is_error(&result, tool_name, &server_name)?;

        Ok(result)
    }

    /// Generic JSON-RPC method dispatch with the same timeout, bounded
    /// reconnect, and error surfacing as `call_tool`. Returns the raw
    /// `result` value; callers apply any method-specific envelope handling.
    pub(crate) async fn dispatch_method(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Map the embedded code: -32601 unknown tool, -32602 invalid params, -32603 internal error — each points at a different fix
  2. Re-fetch tools/list and call the exact advertised name
  3. Validate arguments against the tool's inputSchema before the call
  4. For -32603, inspect the server's own logs; the client surface just relays the server's message

Example fix

// before
let res = server.call_tool("fs_read", json!({"path": p})).await?;

// after: use the advertised name and schema
let tools = list_tools(&server).await?;
let t = tools.iter().find(|t| t.name.contains("read")).context("no read tool")?;
validate_args(&t.input_schema, &args)?;
let res = server.call_tool(&t.name, args).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Resolve the tool name from the live registry, then validate args
let tools = list_tools(&server).await?;
let tool = tools.iter().find(|t| t.name == wanted).context("tool not advertised")?;
validate_against_schema(&args, &tool.input_schema)?;
server.call_tool(&tool.name, args).await?;

Type guard

fn is_jsonrpc_protocol_error(err: &anyhow::Error) -> bool {
    let s = err.to_string();
    s.contains("error -3") // -32601 unknown tool, -32602 invalid params, -32603 internal
}

Try / catch

Catch, extract the code from the message, and branch: -32601 -> refresh tool list and use the advertised name; -32602 -> fix arguments against the schema; -32603 -> inspect server logs, retry only if the server message indicates a transient fault.

Prevention

When it happens

Trigger: Calling a tool name the server never advertised (-32601 method not found); arguments failing JSON-RPC param validation (-32602); server-internal errors returned as -32603; params that cannot be parsed against the expected shape.

Common situations: Tool renamed in a server upgrade while the caller still uses the old name; stale cached tool lists; argument type typos (string vs number) that the tool's inputSchema would have caught.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/e980554c912ce3e5. Report an issue: GitHub.