{"record":{"id":"5193e27faada5510","repo":"Hmbown/CodeWhale","slug":"unsupported-mcp-url","errorCode":null,"errorMessage":"Unsupported MCP URL","messagePattern":"Unsupported MCP URL","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/external_import.rs","lineNumber":209,"sourceCode":"                \"Source contains unsupported OAuth fields\"\n            );\n        }\n        let server: McpServerConfig = serde_json::from_value(config)\n            .map_err(|_| anyhow::anyhow!(\"Invalid MCP entry; contents omitted\"))?;\n        anyhow::ensure!(\n            server.command.is_some() != server.url.is_some(),\n            \"MCP entry must have one target\"\n        );\n        if let Some(command) = &server.command {\n            anyhow::ensure!(\n                !command.trim().is_empty() && !command.chars().any(char::is_control),\n                \"Invalid MCP command\"\n            );\n        }\n        if let Some(url) = &server.url {\n            let parsed =\n                reqwest::Url::parse(url).map_err(|_| anyhow::anyhow!(\"Invalid MCP URL\"))?;\n            anyhow::ensure!(\n                matches!(parsed.scheme(), \"http\" | \"https\")\n                    && parsed.host_str().is_some()\n                    && parsed.username().is_empty()\n                    && parsed.password().is_none(),\n                \"Unsupported MCP URL\"\n            );\n        }\n        super::validate_mcp_transport(server.transport.as_deref())\n            .map_err(|_| anyhow::anyhow!(\"Unsupported MCP transport\"))?;\n        let hard_blocked = !server.is_enabled();\n        out.push(ImportCandidate {\n            summary: server_summary(&name, &server),\n            name,\n            source_kind: kind.clone(),\n            source_path: path.to_path_buf(),\n            content_hash: hash.clone(),\n            hard_blocked,\n            block_reason: hard_blocked.then(|| \"Disabled at its source; cannot import\".into()),","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/external_import.rs#L191-L227","documentation":"The URL parses but fails the safety constraints: the scheme must be http or https, a host must be present, and no userinfo (username/password) may be embedded. This blocks non-HTTP schemes (file:, ws:) and credential-bearing URLs; the error intentionally does not say which predicate failed.","triggerScenarios":"A server entry with url \"file:///opt/mcp/server\"; \"ftp://host/x\"; \"https://user:pass@host\"; or a scheme-less but parseable URL like \"localhost:3000\" (parsed with scheme `localhost`).","commonSituations":"Using a browser-style URL with embedded basic-auth credentials; pointing at a unix socket or local file path; using websocket URLs from another client's config.","solutions":["Switch to `http://` or `https://` with a real host, e.g. `http://127.0.0.1:8080`","Remove any `user:pass@` userinfo from the URL; supply credentials out-of-band (env var/bearer token)","If the server only speaks a non-HTTP protocol, run it as a local command entry instead of a URL entry"],"exampleFix":"// before\n{\"mcpServers\":{\"api\":{\"url\":\"https://user:secret@mcp.example.com\"}}}\n// after\n{\"mcpServers\":{\"api\":{\"url\":\"https://mcp.example.com\",\"bearer_token_env_var\":\"MCP_TOKEN\"}}}","handlingStrategy":"validation","validationCode":"function urlPolicyOk(u) {\n  const p = new URL(u);\n  return [\"http:\",\"https:\"].includes(p.protocol) && !!p.hostname && p.username === \"\" && p.password === \"\";\n}","typeGuard":"function isSafeHttpUrl(u) { try { return urlPolicyOk(u); } catch { return false; } }","tryCatchPattern":"catch, then check scheme, host presence, and userinfo separately to identify which constraint failed","preventionTips":["Never embed user:password in URLs; use bearer_token_env_var instead","Restrict entries to http/https targets","Use command entries for non-HTTP transports"],"tags":["mcp","url","security","validation"],"backgroundTag":"invalid-url","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"}