diff --git a/autumn/src/mcp.rs b/autumn/src/mcp.rs index 97d86ff03..bbb9e24e8 100644 --- a/autumn/src/mcp.rs +++ b/autumn/src/mcp.rs @@ -1826,11 +1826,7 @@ fn build_request( // Use the same full segment encoder the typed path helpers use, so an // MCP call accepts the same values a direct HTTP caller could pass. let encoded = if is_catch_all { - value - .split('/') - .map(crate::paths::encode_path_segment) - .collect::>() - .join("/") + crate::paths::encode_catch_all_param(&value) } else { crate::paths::encode_path_segment(&value) }; diff --git a/autumn/src/paths.rs b/autumn/src/paths.rs index 3574b9614..e974dc0cf 100644 --- a/autumn/src/paths.rs +++ b/autumn/src/paths.rs @@ -58,18 +58,26 @@ pub fn encode_path_segment(value: impl std::fmt::Display) -> String { #[must_use] pub fn encode_catch_all_param(value: impl std::fmt::Display) -> String { let s = value.to_string(); - s.split('/') - .map(|segment| { - if segment == "." { - "%2E".to_string() - } else if segment == ".." { - "%2E%2E".to_string() - } else { - percent_encode(segment) - } - }) - .collect::>() - .join("/") + let mut out = String::with_capacity(s.len() + s.len() / 4); + let mut iter = s.split('/').map(|segment| { + if segment == "." { + "%2E".to_string() + } else if segment == ".." { + "%2E%2E".to_string() + } else { + percent_encode(segment) + } + }); + + if let Some(first) = iter.next() { + out.push_str(&first); + for item in iter { + out.push('/'); + out.push_str(&item); + } + } + + out } /// Percent-encode a query component per RFC 3986.