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

MCP `{rpc_method}` error {}: {}

Error message

MCP `{rpc_method}` error {}: {}

What it means

dispatch_method sent a non-tool JSON-RPC method (resources/list, resources/read, prompts/list, prompts/get) and got a response with a top-level error object set. The message embeds the JSON-RPC code and server message, relaying a protocol-level rejection of that specific method call.

Source

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

        &self,
        rpc_method: &str,
        params: serde_json::Value,
    ) -> Result<serde_json::Value> {
        let tool_timeout = {
            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!("`{rpc_method}`");
        let resp = self
            .dispatch_rpc(rpc_method, params, tool_timeout, &operation)
            .await?;

        if let Some(err) = resp.error {
            bail!("MCP `{rpc_method}` error {}: {}", err.code, err.message);
        }
        let result = resp.result.unwrap_or(serde_json::Value::Null);
        let server_name = self.inner.lock().await.config.name.clone();
        check_result_is_error(&result, rpc_method, &server_name)?;
        Ok(result)
    }

    /// `resources/list` — capability-gated.
    pub async fn list_resources(&self, cursor: Option<String>) -> Result<McpResourcesListResult> {
        {
            let inner = self.inner.lock().await;
            if !inner.capabilities.supports_resources() {
                bail!(
                    "MCP server `{}` does not support resources",
                    inner.config.name
                );
            }
        }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Map the embedded code: -32601 method not found, -32602 invalid params (bad cursor or URI), -32603 server internal
  2. Use cursors only within a single pagination sequence; refetch page one on -32602
  3. Verify the URI or prompt name against what list_resources / list_prompts returned from that same server
  4. For -32603 or auth-shaped errors, reconnect and retry once
Defensive patterns

Strategy: try-catch

Type guard

fn is_jsonrpc_method_error(err: &anyhow::Error) -> bool {
    let s = err.to_string();
    s.contains("MCP `resources/") || s.contains("MCP `prompts/") || s.contains("error -3")
}

Try / catch

Catch per method call: -32602 with a cursor -> restart pagination from page one; unknown URI/prompt -> drop the stale reference; -32603 or auth-shaped messages -> reconnect once and retry.

Prevention

When it happens

Trigger: Passing a stale cursor from a previous resources/list page; a resources/read URI the server does not recognize; prompts/get with an unknown prompt name; a server that declares a capability in initialize but fails the actual method (version drift, auth expiry mid-session).

Common situations: Cursors persisted across sessions after the server changed; URIs copied from a different server; prompt names renamed upstream; tokens expiring between capability discovery and the read.

Related errors


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