Skip to content

fix: reply -32700 on stdio parse errors instead of closing#833

Merged
alexhancock merged 2 commits intomainfrom
fix/issue-825-stdio-parse-error
May 7, 2026
Merged

fix: reply -32700 on stdio parse errors instead of closing#833
alexhancock merged 2 commits intomainfrom
fix/issue-825-stdio-parse-error

Conversation

@DaleSeo
Copy link
Copy Markdown
Member

@DaleSeo DaleSeo commented May 5, 2026

Fixes #825

Motivation and Context

The RMCP stdio transport used to close the stream silently when it encountered a malformed line. This made it hard for clients to tell the difference between a parse failure and a normal end-of-file initiated by the peer. Just one bad byte could bring down the entire session.

Now, the stdio transport responds with a JSON-RPC -32700 Parse error when it receives a malformed line, instead of closing the stream silently. It also removes a leading UTF-8 BOM, so messages from Windows tools that have a BOM prefix can be parsed correctly.

How Has This Been Tested?

Added new tests

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

@DaleSeo DaleSeo self-assigned this May 5, 2026
@github-actions github-actions Bot added T-core Core library changes T-transport Transport layer changes labels May 5, 2026
@DaleSeo DaleSeo force-pushed the fix/issue-825-stdio-parse-error branch 2 times, most recently from 69b254b to 93873ad Compare May 5, 2026 15:06
@DaleSeo DaleSeo marked this pull request as ready for review May 5, 2026 15:10
@DaleSeo DaleSeo requested a review from a team as a code owner May 5, 2026 15:10
alexhancock
alexhancock previously approved these changes May 6, 2026
Comment thread crates/rmcp/src/transport/async_rw.rs Outdated
// Hardcoded bytes because `RequestId` has no `Null` variant — we can't
// build an `id: null` JsonRpcError through the typed codec.
const PARSE_ERROR_RESPONSE: &[u8] =
b"{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32700,\"message\":\"Parse error\"},\"id\":null}\n";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there really no way to build something we can serialize to get this value instead of hardcoding it?

Copy link
Copy Markdown
Member Author

@DaleSeo DaleSeo May 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question, @alexhancock! This was a workaround because JsonRpcError requires its id field and RequestId has no null variant.

I looked into the JSON RPC spec and the MCP spec. I noticed that the MCP spec separated the Response schema into ResultResponse and ErrorResponse in the 2025-11-25 version to match the JSON RPC spec.

2025-06-18 2025-11-25
2026-05-07 at 12 01 33 2026-05-07 at 12 00 56

As seen above, the id field is required for ResultResponse while is optional for ErrorResponse. I checked other SDKs, and they all follow this, so I updated our JsonRpcError::id struct to be optional.

pub struct JsonRpcError {
pub jsonrpc: JsonRpcVersion2_0,
// MCP 2025-11-25 §Error Responses: `id` is optional and omitted when the
// server cannot read the request id (e.g. parse error / invalid request).
// https://modelcontextprotocol.io/specification/2025-11-25/basic#error-responses
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<RequestId>,
pub error: ErrorData,
}

@DaleSeo DaleSeo force-pushed the fix/issue-825-stdio-parse-error branch from cc503e7 to b3858c0 Compare May 7, 2026 15:15
@github-actions github-actions Bot added T-test Testing related changes T-config Configuration file changes T-service Service layer changes labels May 7, 2026
@DaleSeo DaleSeo force-pushed the fix/issue-825-stdio-parse-error branch from 3295a39 to bebee77 Compare May 7, 2026 15:27
@DaleSeo DaleSeo force-pushed the fix/issue-825-stdio-parse-error branch from bebee77 to 690df59 Compare May 7, 2026 15:31
@DaleSeo DaleSeo requested a review from alexhancock May 7, 2026 16:17
@alexhancock alexhancock merged commit 321ab14 into main May 7, 2026
18 checks passed
@alexhancock alexhancock deleted the fix/issue-825-stdio-parse-error branch May 7, 2026 16:27
@github-actions github-actions Bot mentioned this pull request May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-core Core library changes T-service Service layer changes T-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stdio transport: parse errors close stream instead of returning -32700 Parse Error

2 participants