modelcontextprotocol / modelcontextprotocol/rust-sdk

Client accepts JSON-RPC response containing both result and error

Open
#1,283 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P1 ready for work T-model T-service
Dominant language
Rust
Stars
3.9k
Forks
645
Avg merge
4d 13h
Merged PRs (30d)
36

Description

Describe the bug

The rmcp 3.4.0 client accepts a malformed JSON-RPC response containing both result and error. It resolves the pending tools/call as Ok(CallToolResult), using the result and silently ignoring the error.

JSON-RPC responses must contain either result or error, not both.

Environment

  • rmcp: 3.4.0 (rmcp-v3.4.0, commit fd7811f)
  • rustc: 1.98.1
  • macOS arm64
  • Protocol: MCP 2026-07-28
  • Transports: stdio and Streamable HTTP

To reproduce

  1. Connect an rmcp client to an MCP server.
  2. Send a tools/call request.
  3. Have the server return a response shaped like:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": { "content": [], "resultType": "complete" },
  "error": { "code": -32603, "message": "injected error" }
}

A minimal client call is:

let result = client
    .call_tool(
        CallToolRequestParams::new("malformed_message")
            .with_arguments(
                serde_json::json!({"variant": "result-with-error"})
                    .as_object()
                    .unwrap()
                    .clone(),
            ),
    )
    .await;

assert!(result.is_err());

This was found while testing MCP Failure Lab 0.9.0. The malformed_message tool intentionally returned a response containing both result and error.

I reproduced it with the mcp-failure-lab@0.9.0 package and the v0.9.0 Git tag over stdio and Streamable HTTP.

Expected behavior

The client rejects the response as an invalid JSON-RPC message and returns an error for the pending request. The connection may remain usable afterward.

Actual behavior

call_tool returns Ok(CallToolResult). A subsequent normal request succeeds.

Additional context

The likely parser path is the untagged JsonRpcMessage enum: JsonRpcResponse accepts the result shape while Serde ignores the unexpected error field.

Other tested official clients, including C# ModelContextProtocol 2.2.0, reject the same wire response.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the untagged JsonRpcMessage enum through JsonRpcResponse and the call_tool request path. Reproduce the malformed response described in the issue, then add coverage for a response containing both result and error. Done means the pending request returns an error instead of Ok(CallToolResult), while the stated connection behavior is preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.