fix(cr-2026-04-22): MCP stdio replies with parse-error on malformed JSON
MAJOR from the 2026-04-22 review (crates/mcp/src/main.rs:26-30): the stdio transport logged malformed JSON lines to stderr and continued without sending any JSON-RPC response. Clients saw silence instead of the -32700 Parse Error they could key off. handle_message has a parse-error branch for shape mismatch, but it never ran for bytes that failed to parse as JSON at all. Exposes a new public helper kon_mcp::parse_error_response(detail) that mirrors the existing internal error_response pattern, filling id with null per JSON-RPC 2.0 §5.1 (parse error, no id recoverable). main.rs now writes that response out before continuing the read loop. Regression test on the helper asserts: jsonrpc "2.0", id null, code -32700, message starts with "Parse error" and includes the underlying serde detail.
This commit is contained in:
@@ -335,6 +335,16 @@ fn error_response(id: Value, code: i32, message: String) -> JsonRpcResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a JSON-RPC 2.0 Parse Error response (code -32700, id null),
|
||||
/// for use by the stdio transport when a raw line fails to parse as
|
||||
/// JSON at all. `handle_message` covers the shape-mismatch case; this
|
||||
/// helper covers the `serde_json::from_str` failure in `main.rs` so
|
||||
/// clients receive a well-formed JSON-RPC reply instead of silence
|
||||
/// (2026-04-22 review MAJOR).
|
||||
pub fn parse_error_response(detail: &str) -> JsonRpcResponse {
|
||||
error_response(Value::Null, -32700, format!("Parse error: {detail}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -398,6 +408,18 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_error_response_has_jsonrpc_2_0_shape() {
|
||||
let resp = parse_error_response("expected value at line 1 column 1");
|
||||
assert_eq!(resp.jsonrpc, "2.0");
|
||||
assert_eq!(resp.id, Value::Null);
|
||||
assert!(resp.result.is_none());
|
||||
let err = resp.error.expect("parse_error_response must carry an error");
|
||||
assert_eq!(err.code, -32700);
|
||||
assert!(err.message.contains("Parse error"));
|
||||
assert!(err.message.contains("expected value"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unknown_method_returns_method_not_found_error() {
|
||||
let request = json!({
|
||||
|
||||
Reference in New Issue
Block a user