koala73/worldmonitor · error · McpProxySsrfError
serverUrl DNS resolution failed
Error message
serverUrl DNS resolution failed
What it means
assertServerUrlSafe resolves the serverUrl hostname via DNS before fetching, to verify no resolved address is private/reserved. If defaultResolveHostname throws (NXDOMAIN, resolver outage, transient DNS failure), it throws McpProxySsrfError('serverUrl DNS resolution failed', { cause }). A hostname that resolves to zero addresses also fails with a sibling message.
Solutions
- Verify the hostname resolves publicly: run dig/nslookup on it from outside your network
- Fix typos in serverUrl or restore the deleted DNS record
- If the host is internal-only, expose it publicly — the proxy requires public DNS and public addresses
- Check error.cause for the resolver error code (ENOTFOUND vs ETIMEOUT) to distinguish bad name from resolver outage
Example fix
// before serverUrl: 'https://mcp.corp-internal.local/mcp' // ENOTFOUND publicly // after serverUrl: 'https://mcp.acme.dev/mcp' // public A/AAAA records
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight DNS check before registering
import { lookup } from 'node:dns/promises';
async function hostnameResolves(u) { try { return (await lookup(new URL(u).hostname)).address.length > 0; } catch { return false; } } Type guard
null
Try / catch
try { await validateServerUrl(serverUrl); } catch (e) { if (e instanceof McpProxySsrfError && e.message.includes('DNS')) return { error: 'dns_failure', hostname: new URL(serverUrl).hostname }; throw e; } Prevention
- Run dig/nslookup against serverUrl hostnames before registering them
- Avoid internal-only DNS names for public proxies
- Monitor resolver health if you own the DNS provider path
- Check error.cause for ENOTFOUND (bad name) vs ETIMEOUT (resolver outage)
When it happens
Trigger: Registering/calling an MCP server whose serverUrl hostname does not exist (typo, deleted DNS record, split-horizon internal name visible only inside a private VPC), or where the DNS resolver itself is failing/timing out.
Common situations: Typos in serverUrl hostnames; pointing at internal-only DNS names from a public edge function; DNS provider outage; IPv6 AAAA-only records failing in an IPv4 resolver; DNS record recently deleted after a service rename.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- DNS ${recordType} lookup failed: HTTP ${response.status}
- serverUrl hostname is blocked
- callbackUrl DNS resolution returned no addresses
- callbackUrl is not a valid URL
- callbackUrl DNS resolution failed: ${message}
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/2594def34a1eff24.
Report an issue: GitHub.
Appendix: source
Thrown at api/mcp-proxy.ts:344
return records.flat();
}
async function assertServerUrlSafe(url, signal) {
signal?.throwIfAborted();
const hostname = url.hostname.toLowerCase();
if (BLOCKED_HOSTNAMES.has(hostname)) {
throw new McpProxySsrfError('serverUrl hostname is blocked');
}
if (isBlockedResolvedAddress(hostname)) {
throwBlockedAddress(hostname);
}
let resolvedAddresses;
try {
resolvedAddresses = await defaultResolveHostname(hostname, signal);
} catch (error) {
signal?.throwIfAborted();
throw new McpProxySsrfError('serverUrl DNS resolution failed', { cause: error });
}
signal?.throwIfAborted();
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() ultimatelyView on GitHub (pinned to 7d06c8633d)