Hmbown/CodeWhale · error
MCP HTTP redirect must not contain credentials
Error message
MCP HTTP redirect must not contain credentials
What it means
When following an MCP HTTP redirect, the target Location URL is checked for embedded credentials. If a server redirects to a URL containing user:password@, the client refuses with this error to prevent credential handling on untrusted redirect targets.
Solutions
- Fix the server to redirect to a credential-free URL and authenticate via headers at the target
- Redirect to the bare origin/path and send the Authorization header on the follow-up request
- If you control the hop, remove userinfo from the Location header
Defensive patterns
Strategy: validation
Validate before calling
fn redirect_target_is_clean(base: &Url, location: &str) -> bool {
base.join(location).ok()
.map(|u| !(!u.username().is_empty() || u.password().is_some()))
.unwrap_or(false)
} Try / catch
if let Err(e) = client.execute(req).await {
if e.to_string().contains("redirect must not contain credentials") {
// server-side fix required: strip userinfo from Location
}
} Prevention
- Audit server redirect headers (curl -I) for embedded userinfo
- Never copy curl-style authenticated URLs into redirect configs
- Authenticate at the target with headers, not the URL
When it happens
Trigger: execute_inner follows a 3xx response whose Location header parses (after url.join) to a URL with a non-empty username or a password, i.e. url_has_credentials(&next_url) is true.
Common situations: A misbehaving or compromised server redirecting to an auth-embedded URL; a staging gateway that bakes basic-auth into redirect targets; a hand-written Location header copied from a curl example.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- MCP HTTP discovered URL must not contain credentials
- MCP HTTP redirect would downgrade HTTPS
- MCP HTTP URL must not contain credentials; use configured…
- MCP redirect leaves the reviewed plugin origin
- bundle redirects may not change URL scheme
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/9a416c197afa3f6b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp/http_client.rs:131
let next_request = request
.try_clone()
.context("MCP request body cannot be replayed")?;
let response = client.execute(request).await?;
if !follow_redirects
|| !matches!(response.status().as_u16(), 301 | 302 | 303 | 307 | 308)
{
return Ok(response);
}
let Some(location) = response.headers().get(header::LOCATION) else {
return Ok(response);
};
if redirect_count == 5 {
bail!("MCP HTTP redirect limit exceeded");
}
let next_url = url.join(location.to_str().context("invalid MCP redirect Location")?)?;
validate_url(&next_url)?;
if url_has_credentials(&next_url) {
bail!("MCP HTTP redirect must not contain credentials");
}
if url.scheme() == "https" && next_url.scheme() != "https" {
bail!("MCP HTTP redirect would downgrade HTTPS");
}
request = next_request;
if (matches!(response.status().as_u16(), 301 | 302) && request.method() == Method::POST)
|| (response.status().as_u16() == 303 && request.method() != Method::HEAD)
{
*request.method_mut() = Method::GET;
*request.body_mut() = None;
request.headers_mut().remove(header::CONTENT_TYPE);
request.headers_mut().remove(header::CONTENT_LENGTH);
request.headers_mut().remove(header::TRANSFER_ENCODING);
}
if next_url.origin() != url.origin() {
// Custom headers can contain credentials under arbitrary names;
// retaining just Authorization/ Cookie exclusions is insufficient.
let mut headers = header::HeaderMap::new();View on GitHub (pinned to 73e0f67d83)