Hmbown/CodeWhale · error · ConversionError

Use a canonical numeric MCP address.

Error message

Use a canonical numeric MCP address.

What it means

remote_server() canonicalizes numeric host addresses (IP literals) and raises this error when the host is a numeric/IPv6 form but not in its canonical spelling (str(ipaddress.ip_address(host)) != host), or when ipaddress itself rejects the host.

Solutions

  1. Spell the address in canonical form: use dotted-quad IPv4 exactly as ip_address() prints it, or the compressed IPv6 form
  2. Run python -c "import ipaddress; print(ipaddress.ip_address('YOUR_HOST'))" to get the canonical spelling
  3. Prefer an ASCII DNS hostname instead of a numeric address

Example fix

// before
"url": "http://0x7f000001:8080"
// after
"url": "http://127.0.0.1:8080"
Defensive patterns

Strategy: validation

Validate before calling

import ipaddress
addr = ipaddress.ip_address(host)  # raises for non-canonical/invalid forms
assert str(addr) == host, "use canonical numeric address"

Type guard

def is_canonical_ip(host: str) -> bool:
    try:
        return str(ipaddress.ip_address(host)) == host
    except ValueError:
        return False

Prevention

When it happens

Trigger: Hostnames ending in a purely numeric or hex last label (e.g. '0x7f.1', '2130706433') that don't match their canonical IP form, or malformed IPv6 strings that fail ipaddress parsing.

Common situations: Using integer or hex shorthand for IPs ('127.1', '0x7f000001'); non-canonical IPv6 like '2001:db8::1:0:0:1' vs compressed form; leading-zero IPv4 octets.

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@433685b202 (2026-09-15). Data as JSON: /api/errors/680e9fe97f3f1919. Report an issue: GitHub.

Appendix: source

Thrown at scripts/convert-plugin.py:243

        parsed = urlsplit(url)
        host = parsed.hostname
        require(bool(host) and parsed.port != 0, "MCP URL needs a valid host and port.")
    except ValueError:
        raise ConversionError("Invalid MCP endpoint URL.") from None
    require(parsed.scheme == "https" or (parsed.scheme == "http" and host in {"localhost", "127.0.0.1", "::1"}),
            "MCP endpoints need HTTPS (or explicit loopback HTTP).")
    require(parsed.username is None and parsed.password is None and not parsed.query and not parsed.fragment,
            "MCP URLs must not contain credentials, query strings or fragments.")
    require(host.isascii() and len(url) <= 4096, "Use an ASCII MCP hostname and URL of at most 4096 characters.")
    # URL implementations disagree on shorthand/hex IPv4 spellings. Emit only
    # canonical numeric hosts so the reviewed native host set is identical.
    if ":" in host or re.fullmatch(r"(?:[0-9]+|0x[0-9a-f]+)", host.rsplit(".", 1)[-1]):
        try:
            address = ipaddress.ip_address(host)
            require(str(address) == host, "Use a canonical numeric MCP address.")
            host = f"[{host}]" if address.version == 6 else host
        except ValueError:
            raise ConversionError("Use a canonical numeric MCP address.") from None
    headers = mapping(config.get("headers", {}))
    require(len(headers) <= 64, "At most 64 environment-backed headers are supported.")
    env_headers = {}
    seen_headers = set()
    for key, value in headers.items():
        require(re.fullmatch(r"[A-Za-z0-9!#$%&'*+.^_`|~-]+", key) is not None, "Invalid HTTP header name.")
        require(key.lower() not in seen_headers and key.lower() not in {"accept", "content-type"},
                "HTTP header names must be unique ignoring case; Accept and Content-Type belong to the native transport.")
        seen_headers.add(key.lower())
        require(isinstance(value, str), "HTTP headers must reference environment variable names.")
        reference = re.fullmatch(r"\{env:([A-Za-z_][A-Za-z0-9_]*)\}", value) if dialect != "dsh" else None
        require(reference is not None, "Literal headers, DSH expressions and file interpolation cannot be converted; author native env_headers manually.")
        env_headers[key] = reference[1]
    if env_headers:
        extension["env_headers"] = env_headers
    return {"type": "streamable-http", "url": url,
            "extensions": {"net.codewhale": extension}}, host

View on GitHub (pinned to 433685b202)