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
- Spell the address in canonical form: use dotted-quad IPv4 exactly as ip_address() prints it, or the compressed IPv6 form
- Run python -c "import ipaddress; print(ipaddress.ip_address('YOUR_HOST'))" to get the canonical spelling
- 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
- Prefer DNS hostnames over numeric IP literals
- Never use hex/integer IP shorthand or leading-zero octets
- Get the canonical form via python -c "import ipaddress; print(ipaddress.ip_address(h))"
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
- Invalid MCP endpoint URL.
- Invalid MCP URL
- MCP HTTP requires an http:// or https:// URL with a host
- MCP HTTP URL must not contain credentials; use configured…
- MCP server URL ' ' must include a host
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)