From 35841220fcc35c375922976cef6043fabbf1534e Mon Sep 17 00:00:00 2001 From: hugocasa Date: Mon, 12 Oct 2026 14:39:52 +0200 Subject: [PATCH] fix: fail closed when an mcp error message has no status prefix Co-Authored-By: Claude Opus 5.5 --- backend/windmill-mcp/src/client/redacting.rs | 31 +++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/backend/windmill-mcp/src/client/redacting.rs b/backend/windmill-mcp/src/client/redacting.rs index 0024ed6162..6abcc50f50 100644 --- a/backend/windmill-mcp/src/client/redacting.rs +++ b/backend/windmill-mcp/src/client/redacting.rs @@ -26,7 +26,8 @@ async fn redacted(request: impl Future>) -> Result< // An owned message is `HTTP : `, and the body is the server's // to write: a common one echoes the request target (`Cannot POST /mcp/`). Err(StreamableHttpError::UnexpectedServerResponse(Cow::Owned(message))) => { - let status = message.split(": ").next().unwrap_or_default().to_string(); + let status = message.split_once(": ").map_or("", |(status, _)| status); + let status = status.to_string(); Err(StreamableHttpError::UnexpectedServerResponse(status.into())) } r => r, @@ -120,3 +121,31 @@ impl StreamableHttpClient for UrlRedactingClient { .await } } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn server_error_body_is_dropped() { + for (message, expected) in [ + ( + "HTTP 404 Not Found: Cannot POST /mcp/KEY", + "HTTP 404 Not Found", + ), + ("Cannot POST /mcp/KEY", ""), + ] { + let err = redacted(async { + Err::<(), Error>(StreamableHttpError::UnexpectedServerResponse( + message.to_string().into(), + )) + }) + .await + .unwrap_err(); + let StreamableHttpError::UnexpectedServerResponse(got) = err else { + panic!("unexpected variant: {err}"); + }; + assert_eq!(got, expected); + } + } +}