Hmbown/CodeWhale · error
MCP HTTP redirect would downgrade HTTPS
Error message
MCP HTTP redirect would downgrade HTTPS
What it means
A redirect from an https:// MCP endpoint to a non-https target (http:, or another scheme) is rejected. Downgrading transport security mid-redirect would expose MCP traffic and headers to interception, so the client refuses to follow.
Solutions
- Fix the server/proxy to emit https:// redirect targets (set X-Forwarded-Proto correctly, use relative Locations)
- Point the client directly at the final https URL, skipping the redirect chain
- If the target genuinely only supports http, configure the client against an explicit http:// endpoint at the operator level (accepting the security implications)
Example fix
// before (server config)
return redirect("http://example.com/mcp");
// after
return redirect("https://example.com/mcp"); // or relative "/mcp" Defensive patterns
Strategy: validation
Validate before calling
let u = Url::parse(endpoint)?;
if u.scheme() != "https" {
// decide up front: use https endpoint or explicitly configure http
} Try / catch
if let Err(e) = client.execute(req).await {
if e.to_string().contains("would downgrade HTTPS") {
// fix proxy X-Forwarded-Proto / Location scheme server-side
}
} Prevention
- Set X-Forwarded-Proto correctly on TLS-terminating proxies
- Prefer relative Location headers in server redirects
- Only ever configure https:// MCP endpoints
When it happens
Trigger: execute_inner processes a redirect where the current URL scheme is https but the joined next_url scheme is not https — e.g. Location: http://example.com/mcp.
Common situations: Reverse proxy emitting absolute http:// Location headers behind TLS termination; misconfigured X-Forwarded-Proto so the app generates http redirect URLs; server redirecting to a plain-HTTP health/login endpoint.
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 must not contain credentials
- MCP redirect leaves the reviewed plugin origin
- bundle redirects may not change URL scheme
- MCP HTTP destination blocked by network policy
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/42f4d69a27259712.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp/http_client.rs:134
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();
for name in [header::ACCEPT, header::CONTENT_TYPE] {
if let Some(value) = request.headers().get(&name) {
headers.insert(name, value.clone());View on GitHub (pinned to 73e0f67d83)