From 588e54f84dfc47f7f2ebb903aef69a542eada47f Mon Sep 17 00:00:00 2001 From: cyq <15000851237@163.com> Date: Tue, 2 Jun 2026 03:43:04 +0800 Subject: [PATCH] fix(mcp): surface invalid stdio output --- crates/tui/src/mcp.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/tui/src/mcp.rs b/crates/tui/src/mcp.rs index c07fe5ac..dda1daa0 100644 --- a/crates/tui/src/mcp.rs +++ b/crates/tui/src/mcp.rs @@ -196,6 +196,22 @@ async fn bounded_body_excerpt(response: reqwest::Response, max_bytes: usize) -> format!("{}{}", redact_body_preview(&one_line), suffix) } +fn invalid_json_preview(bytes: &[u8]) -> String { + let body_text = String::from_utf8_lossy(bytes); + if body_text.is_empty() { + return "".to_string(); + } + + let trimmed: String = body_text.chars().take(ERROR_BODY_PREVIEW_BYTES).collect(); + let suffix = if body_text.len() > trimmed.len() { + "…" + } else { + "" + }; + let one_line = trimmed.replace(['\n', '\r'], " "); + format!("{}{}", redact_body_preview(&one_line), suffix) +} + // === Configuration Types === /// Full MCP configuration from mcp.json @@ -1824,7 +1840,11 @@ impl McpConnection { self.state = ConnectionState::Disconnected; })?; let value: serde_json::Value = serde_json::from_slice(&bytes).with_context(|| { - format!("Invalid MCP JSON-RPC message from server '{}'", self.name) + format!( + "Invalid MCP JSON-RPC message from server '{}': {}", + self.name, + invalid_json_preview(&bytes) + ) })?; // Check if this is a response with the expected id. We emit @@ -3379,6 +3399,25 @@ mod tests { assert_eq!(sent[0]["method"], "tools/call"); } + #[tokio::test] + async fn call_method_invalid_json_includes_server_output_preview() { + let sent = Arc::new(Mutex::new(Vec::new())); + let transport = ScriptedValueTransport { + sent: Arc::clone(&sent), + responses: VecDeque::from([b"Allow Burp MCP connection? [y/N]".to_vec()]), + }; + let mut conn = test_connection(Box::new(transport)); + + let err = conn + .call_method("tools/call", serde_json::json!({"name": "burp"}), 1) + .await + .expect_err("non-json MCP stdout should fail"); + let msg = err.to_string(); + + assert!(msg.contains("Invalid MCP JSON-RPC message from server 'mock'")); + assert!(msg.contains("Allow Burp MCP connection")); + } + #[tokio::test] async fn call_method_times_out_while_waiting_for_response() { let sent = Arc::new(Mutex::new(Vec::new()));