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
- Map the embedded code: -32601 method not found, -32602 invalid params (bad cursor or URI), -32603 server internal
- Use cursors only within a single pagination sequence; refetch page one on -32602
- Verify the URI or prompt name against what list_resources / list_prompts returned from that same server
- 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
- Keep cursors scoped to a single pagination run
- Verify URIs and prompt names against list_resources/list_prompts from the same server and session
- Reconnect on long-lived sessions so mid-session auth expiry surfaces as a clean retry
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
- MCP tool `{tool_name}` error {}: {}
- MCP server `{server_name}` rejected initialize: {:?}
- MCP `{op}` (server `{server_name}`) returned isError: {detai
- MCP server `{server_name}` timed out after {timeout_secs}s d
- MCP server `{}` does not support resources
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/dd21385dae75271c.
Report an issue: GitHub.