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:
@@ -23,18 +23,22 @@ async fn main() -> anyhow::Result<()> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let raw: serde_json::Value = match serde_json::from_str(trimmed) {
|
||||
Ok(value) => value,
|
||||
let response = match serde_json::from_str::<serde_json::Value>(trimmed) {
|
||||
Ok(raw) => match kon_mcp::handle_message(&pool, raw).await {
|
||||
Some(response) => response,
|
||||
None => continue, // notification — no reply
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("[kon-mcp] ignoring malformed line: {err}");
|
||||
continue;
|
||||
// Per JSON-RPC 2.0 §5.1: a Parse Error responds with
|
||||
// code -32700 and id null. Previously this branch
|
||||
// logged and continued, dropping the response —
|
||||
// clients saw silence instead of a structured error
|
||||
// (2026-04-22 review MAJOR).
|
||||
eprintln!("[kon-mcp] parse error: {err}");
|
||||
kon_mcp::parse_error_response(&err.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
let Some(response) = kon_mcp::handle_message(&pool, raw).await else {
|
||||
continue; // notification — no reply
|
||||
};
|
||||
|
||||
let payload = serde_json::to_string(&response)?;
|
||||
stdout.write_all(payload.as_bytes()).await?;
|
||||
stdout.write_all(b"\n").await?;
|
||||
|
||||
Reference in New Issue
Block a user