{"record":{"id":"e06299c468b16e3e","repo":"Hmbown/CodeWhale","slug":"mcp-http-requires-an-http-or-https-url-with-a-host","errorCode":null,"errorMessage":"MCP HTTP requires an http:// or https:// URL with a host","messagePattern":"MCP HTTP requires an http:// or https:// URL with a host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/http_client.rs","lineNumber":235,"sourceCode":"        Ok(client)\n    }\n}\n\nfn validate_network_policy(url: &Url, network_policy: Option<&NetworkPolicyDecider>) -> Result<()> {\n    let host = url.host_str().context(\"MCP URL has no host\")?;\n    if let Some(policy) = network_policy {\n        match policy.evaluate(host, \"mcp\") {\n            Decision::Allow => {}\n            Decision::Deny => bail!(\"MCP HTTP destination blocked by network policy\"),\n            Decision::Prompt => bail!(\"MCP HTTP destination requires network approval\"),\n        }\n    }\n    Ok(())\n}\n\nfn validate_url(url: &Url) -> Result<()> {\n    if !matches!(url.scheme(), \"http\" | \"https\") || url.host_str().is_none() {\n        bail!(\"MCP HTTP requires an http:// or https:// URL with a host\");\n    }\n    Ok(())\n}\n\nfn url_has_credentials(url: &Url) -> bool {\n    !url.username().is_empty() || url.password().is_some()\n}\n\nimpl McpHttpClient {\n    async fn public_dns_pin(&self, url: &Url) -> Result<Option<(String, SocketAddr)>> {\n        let host = url.host_str().context(\"MCP URL has no host\")?;\n        let literal = host.trim_start_matches('[').trim_end_matches(']');\n        if let Ok(ip) = literal.parse::<IpAddr>() {\n            if is_restricted_ip(&ip) {\n                bail!(\"MCP HTTP destination is a restricted IP address\");\n            }\n            return Ok(None);\n        }","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/http_client.rs#L217-L253","documentation":"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.","triggerScenarios":"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.","commonSituations":"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://.","solutions":["Configure the endpoint with an absolute http:// or https:// URL including the host","Fix the server's redirect to return an absolute Location with http(s) scheme and host","Validate the URL string with Url::parse and check scheme/host before passing it to the client"],"exampleFix":"// before\nMcpHttpClient::new(\"example.com/mcp\", ...)?   // no scheme -> error\n// after\nMcpHttpClient::new(\"https://example.com/mcp\", ...)?","handlingStrategy":"validation","validationCode":"let u = Url::parse(endpoint).context(\"invalid MCP HTTP endpoint\")?;\nif !matches!(u.scheme(), \"http\" | \"https\") || u.host_str().is_none() {\n    return Err(\"endpoint must be absolute http(s) URL with a host\");\n}","typeGuard":"fn is_valid_mcp_http_url(s: &str) -> bool {\n    Url::parse(s).map(|u| {\n        matches!(u.scheme(), \"http\" | \"https\") && u.host_str().is_some()\n    }).unwrap_or(false)\n}","tryCatchPattern":"match McpHttpClient::new(url, ...).await {\n    Err(e) if e.to_string().contains(\"requires an http:// or https:// URL\") => {\n        // normalize: prepend scheme or reject config at load time\n    }\n    other => other?,\n}","preventionTips":["Validate MCP endpoint strings at config-load time with Url::parse","Require explicit scheme in config schema (reject bare host:port)","Check redirect Location headers resolve to absolute http(s) URLs before trusting them"],"tags":["mcp","http","url","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}