{"record":{"id":"5e81466577e9ae59","repo":"Hmbown/CodeWhale","slug":"invalid-mcp-endpoint-url","errorCode":null,"errorMessage":"Invalid MCP endpoint URL.","messagePattern":"Invalid MCP endpoint URL\\.","errorType":"validation","errorClass":"ConversionError","httpStatus":null,"severity":"error","filePath":"scripts/convert-plugin.py","lineNumber":229,"sourceCode":"\ndef remote_server(config, dialect, defaults):\n    mapping(config)\n    if dialect == \"dsh\":\n        require(config.get(\"transport\") == \"streamable-http\", \"Unsupported MCP transport.\")\n        mapping(config, {\"serverName\", \"transport\", \"url\", \"headers\", \"toolCallTimeoutMs\", \"failOnStartupError\"})\n    else:\n        require(config.get(\"type\") == \"remote\", \"Unsupported MCP transport.\")\n        mapping(config, {\"type\", \"url\", \"headers\", \"oauth\", \"enabled\" if dialect == \"opencode-v1\" else \"disabled\", \"timeout\"})\n        require(config.get(\"oauth\") is False, \"Set oauth:false explicitly; plugin OAuth and upstream auto-OAuth cannot be converted.\")\n    extension = server_options(config, dialect, defaults)\n    url = config.get(\"url\")\n    require(isinstance(url, str) and not re.search(r\"[\\s\\\\{}]\", url), \"MCP URL must be a literal endpoint without interpolation.\")\n    try:\n        parsed = urlsplit(url)\n        host = parsed.hostname\n        require(bool(host) and parsed.port != 0, \"MCP URL needs a valid host and port.\")\n    except ValueError:\n        raise ConversionError(\"Invalid MCP endpoint URL.\") from None\n    require(parsed.scheme == \"https\" or (parsed.scheme == \"http\" and host in {\"localhost\", \"127.0.0.1\", \"::1\"}),\n            \"MCP endpoints need HTTPS (or explicit loopback HTTP).\")\n    require(parsed.username is None and parsed.password is None and not parsed.query and not parsed.fragment,\n            \"MCP URLs must not contain credentials, query strings or fragments.\")\n    require(host.isascii() and len(url) <= 4096, \"Use an ASCII MCP hostname and URL of at most 4096 characters.\")\n    # URL implementations disagree on shorthand/hex IPv4 spellings. Emit only\n    # canonical numeric hosts so the reviewed native host set is identical.\n    if \":\" in host or re.fullmatch(r\"(?:[0-9]+|0x[0-9a-f]+)\", host.rsplit(\".\", 1)[-1]):\n        try:\n            address = ipaddress.ip_address(host)\n            require(str(address) == host, \"Use a canonical numeric MCP address.\")\n            host = f\"[{host}]\" if address.version == 6 else host\n        except ValueError:\n            raise ConversionError(\"Use a canonical numeric MCP address.\") from None\n    headers = mapping(config.get(\"headers\", {}))\n    require(len(headers) <= 64, \"At most 64 environment-backed headers are supported.\")\n    env_headers = {}\n    seen_headers = set()","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/convert-plugin.py#L211-L247","documentation":"remote_server() validates MCP server endpoint URLs and raises this ConversionError when Python's urlsplit itself fails to parse the URL — malformed syntax that urlsplit cannot turn into a structured result.","triggerScenarios":"A URL that makes parsed.port or hostname access raise ValueError: unparseable port (e.g. 'https://host:notaport'), malformed IPv6 brackets, or otherwise invalid URL syntax.","commonSituations":"Typos in the port field; unbracketed IPv6 literals; template placeholders left in config like {{PORT}}; URLs copied with trailing garbage.","solutions":["Fix the URL so urlsplit parses it: bracket IPv6 hosts, use a numeric port","Remove template placeholders and interpolate real values before conversion","Prefer a canonical https://host:port form and re-run the converter"],"exampleFix":"// before\nurl: \"http://[::1:notaport\"\n// after\nurl: \"http://[::1]:8080\"","handlingStrategy":"validation","validationCode":"from urllib.parse import urlsplit\np = urlsplit(url)\nassert p.scheme in (\"http\", \"https\") and p.hostname and p.port is not None","typeGuard":"def looks_like_valid_url(url: str) -> bool:\n    try:\n        return bool(urlsplit(url).hostname)\n    except ValueError:\n        return False","tryCatchPattern":"try:\n    validate_mcp_url(url)\nexcept ValueError as e:\n    log.error(\"malformed MCP URL %r: %s\", url, e)","preventionTips":["Interpolate templates before validation","Bracket IPv6 literals","Always include an explicit numeric port"],"tags":["python","url","mcp"],"backgroundTag":"invalid-url-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}