koala73/worldmonitor · error · McpProxySsrfError

serverUrl DNS resolution failed

Error message

serverUrl DNS resolution failed: ${message}

What it means

SSRF guard error in the MCP proxy's assertServerUrlSafe: resolving the hostname's A/AAAA records via DoH threw (network, timeout, or DNS status failure), so safety could not be established. The underlying error message is embedded; the request is refused rather than allowed through unverified.

Solutions

  1. Retry — transient DoH failures resolve on retry
  2. Verify the hostname resolves publicly (dig/nslookup from another host)
  3. If the DoH endpoint is unreachable from the edge runtime, fix egress or the DNS_JSON_ENDPOINT configuration
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at api/mcp-proxy.ts:168 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21). Data as JSON: /api/errors/d5dd50f418898a25. Report an issue: GitHub.

Appendix: source

Thrown at api/mcp-proxy.ts:170

 * OPTIONS preflights are deliberately NOT emitted — a static 204 that cannot
 * fail would double row volume for no diagnostic value. /mcp skips them too
 * (McpUsage.skip).
 */
function emitProxyUsage(req, status: number, durationMs: number, ctx, callerIdentity = null): void {
  if (!ctx) return;
  try {
    const usageIdentity = proxyUsageIdentityFor(req, callerIdentity);
    emitUsageEvents(ctx, [buildRequestEvent({
      requestId: deriveRequestId(req),
      domain: 'mcp',
      route: '/api/mcp-proxy',
      method: req.method,
      status,
      // Measured from handler entry, so this INCLUDES the auth/rate-limit
      // gates — unlike logProxyCall's `started`, which begins after auth.
      // The usage row is the end-to-end caller-visible latency.
      durationMs,
      reqBytes: deriveReqBytes(req),
      // Not tracked: the proxy streams upstream bodies through bounded readers
      // and jsonResponse sets no content-length, so there is no byte count to
      // report without buffering a second time. Size questions belong to
      // MAX_MCP_PROXY_RESPONSE_BYTES, not to this row.
      resBytes: 0,
      customerId: usageIdentity.customer_id,
      principalId: usageIdentity.principal_id,
      authKind: usageIdentity.auth_kind,
      tier: usageIdentity.tier,
      planKey: usageIdentity.plan_key,
      country: deriveCountry(req),
      ipCity: deriveIpCity(req),
      ipRegion: deriveIpRegion(req),
      executionRegion: deriveExecutionRegion(req),
      executionPlane: 'vercel-edge',
      originKind: 'mcp',
      cacheTier: 'no-store',
      ip: deriveIp(req),

View on GitHub (pinned to 7d06c8633d)