Hmbown/CodeWhale · error

MCP HTTP requires an http:// or https:// URL with a host

Error message

MCP HTTP requires an http:// or https:// URL with a host

What it means

MCP HTTP transport only supports absolute http:// or https:// URLs that carry a host. validate_url rejects anything else (unix:, file:, ws:, or host-less URLs) before any request is made. This is a structural validation of the endpoint, separate from policy or credential checks.

Solutions

  1. Configure the endpoint with an absolute http:// or https:// URL including the host
  2. Fix the server's redirect to return an absolute Location with http(s) scheme and host
  3. Validate the URL string with Url::parse and check scheme/host before passing it to the client

Example fix

// before
McpHttpClient::new("example.com/mcp", ...)?   // no scheme -> error
// after
McpHttpClient::new("https://example.com/mcp", ...)?
Defensive patterns

Strategy: validation

Validate before calling

let u = Url::parse(endpoint).context("invalid MCP HTTP endpoint")?;
if !matches!(u.scheme(), "http" | "https") || u.host_str().is_none() {
    return Err("endpoint must be absolute http(s) URL with a host");
}

Type guard

fn is_valid_mcp_http_url(s: &str) -> bool {
    Url::parse(s).map(|u| {
        matches!(u.scheme(), "http" | "https") && u.host_str().is_some()
    }).unwrap_or(false)
}

Try / catch

match McpHttpClient::new(url, ...).await {
    Err(e) if e.to_string().contains("requires an http:// or https:// URL") => {
        // normalize: prepend scheme or reject config at load time
    }
    other => other?,
}

Prevention

When it happens

Trigger: McpHttpClient::new, execute_inner (after joining a redirect Location), or client_for_target passes a URL to validate_url whose scheme is not http/https or which has no host_str — e.g. a relative redirect Location joined to a base producing a host-less URL, or an endpoint configured as "localhost/mcp" without a scheme.

Common situations: Config entry missing the scheme ("example.com/mcp"); accidental ws:// or file:// endpoint; relative or empty Location header in a redirect that joins into an invalid URL; typo like htp://.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/e06299c468b16e3e. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/mcp/http_client.rs:235

        Ok(client)
    }
}

fn validate_network_policy(url: &Url, network_policy: Option<&NetworkPolicyDecider>) -> Result<()> {
    let host = url.host_str().context("MCP URL has no host")?;
    if let Some(policy) = network_policy {
        match policy.evaluate(host, "mcp") {
            Decision::Allow => {}
            Decision::Deny => bail!("MCP HTTP destination blocked by network policy"),
            Decision::Prompt => bail!("MCP HTTP destination requires network approval"),
        }
    }
    Ok(())
}

fn validate_url(url: &Url) -> Result<()> {
    if !matches!(url.scheme(), "http" | "https") || url.host_str().is_none() {
        bail!("MCP HTTP requires an http:// or https:// URL with a host");
    }
    Ok(())
}

fn url_has_credentials(url: &Url) -> bool {
    !url.username().is_empty() || url.password().is_some()
}

impl McpHttpClient {
    async fn public_dns_pin(&self, url: &Url) -> Result<Option<(String, SocketAddr)>> {
        let host = url.host_str().context("MCP URL has no host")?;
        let literal = host.trim_start_matches('[').trim_end_matches(']');
        if let Ok(ip) = literal.parse::<IpAddr>() {
            if is_restricted_ip(&ip) {
                bail!("MCP HTTP destination is a restricted IP address");
            }
            return Ok(None);
        }

View on GitHub (pinned to 73e0f67d83)