Skip to content

Client accepts JSON-RPC response containing both result and error #1283

Description

@anilloutombam

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High: significant functionality gap or spec violationT-modelModel/data structure changesT-serviceService layer changesbugSomething is not workingready for workIssue is well-defined and ready to be picked up

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions