koala73/worldmonitor · error · McpProxySsrfError
serverUrl DNS resolution returned no addresses
Error message
serverUrl DNS resolution returned no addresses
What it means
Thrown by assertServerUrlSafe when defaultResolveHostname resolved without throwing but returned an empty array — the hostname has no A or AAAA records (NXDOMAIN-style). The proxy refuses to forward to a host with no resolvable address because there is nothing to SSRF-check or connect to.
Source
Thrown at api/mcp-proxy.ts:172
async function assertServerUrlSafe(url) {
const hostname = url.hostname.toLowerCase();
if (BLOCKED_HOSTNAMES.has(hostname)) {
throw new McpProxySsrfError(`serverUrl hostname is blocked: ${hostname}`);
}
if (isBlockedResolvedAddress(hostname)) {
throwBlockedAddress(hostname);
}
let resolvedAddresses;
try {
resolvedAddresses = await defaultResolveHostname(hostname);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new McpProxySsrfError(`serverUrl DNS resolution failed: ${message}`);
}
if (!resolvedAddresses.length) {
throw new McpProxySsrfError('serverUrl DNS resolution returned no addresses');
}
const blocked = resolvedAddresses.find(isBlockedResolvedAddress);
if (blocked) {
throwBlockedAddress(blocked);
}
return { url, resolvedAddresses };
}
// Vercel Edge fetch does not expose a Node-style lookup/socket hook, so this
// proxy CANNOT pin the TLS connection to a previously vetted address. There is
// no way to guarantee that the IP we validated is the IP fetch() ultimately
// connects to; a DNS answer can change between our resolve and fetch's own
// resolve. This re-resolve-and-recheck immediately before every outbound
// dispatch NARROWS that DNS-rebinding window but does not close it. The
// residual rebind window is an ACCEPTED limitation of the Edge runtime (no
// socket-level pin available) — documented, not fixed here (P2, issue #5061).View on GitHub (pinned to ffec79ac33)
Solutions
- Verify the hostname spelling and registration.
- Ensure the host has at least one A or AAAA record: `dig +short A <host>` / `dig +short AAAA <host>`.
- Provision an A/AAAA record at the DNS provider and retry.
Example fix
// before
proxy({ serverUrl: 'https://mcp.typo.exmaple.com/mcp' })
// after
proxy({ serverUrl: 'https://mcp.example.com/mcp' }) Defensive patterns
Strategy: validation
Validate before calling
async function hostHasAddressRecord(hostname: string): Promise<boolean> {
const r = await fetch(`https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(hostname)}&type=A`, {
headers: { Accept: 'application/dns-json' },
signal: AbortSignal.timeout(2000),
});
const data = await r.json();
return Array.isArray(data?.Answer) && data.Answer.some(a => a?.type === 1);
} Try / catch
try {
await assertServerUrlSafe(new URL(serverUrl));
} catch (err) {
if (err.name === 'McpProxySsrfError' && err.message === 'serverUrl DNS resolution returned no addresses') {
return res.status(400).json({ error: 'The MCP server host has no DNS address record.' });
}
throw err;
} Prevention
- Verify the MCP server host has A/AAAA records before registering.
- Make sure DNS is provisioned before first use.
- Surface 'no addresses' as a user-correctable config error.
When it happens
Trigger: POST /api/mcp-proxy with a serverUrl whose hostname does not exist, has been de-registered, or has only non-address records (MX/TXT only).
Common situations: Typo in the MCP server host; a domain not yet provisioned; an expired domain; a hostname that only has MX records.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- serverUrl DNS resolution failed: ${message}
- Webhook URL DNS resolution returned no addresses
- serverUrl host is not allowed
- serverUrl hostname is blocked: ${hostname}
- Webhook URL is not a valid URL
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/77c5f2e62b87f0c9.
Report an issue: GitHub.