{"record":{"id":"1905f1b3842a17c3","repo":"koala73/worldmonitor","slug":"mcp-server-request-failed","errorCode":null,"errorMessage":"MCP server request failed","messagePattern":"MCP server request failed","errorType":"exception","errorClass":"McpProxyUpstreamError","httpStatus":null,"severity":"error","filePath":"api/mcp-proxy.ts","lineNumber":271,"sourceCode":"  const isTimeout = (error instanceof Error && error.name === 'TimeoutError')\n    || message.includes('TimeoutError')\n    || message.includes('timed out');\n  const isExpectedExternal = error instanceof McpProxyUpstreamError\n    || error instanceof McpProxySsrfError\n    || error instanceof ResponseBodyTooLargeError\n    || error instanceof McpProxyJsonDepthError;\n  return {\n    isTimeout,\n    level: isTimeout || isExpectedExternal ? 'warning' : 'error',\n  };\n}\n\nasync function fetchMcpUpstream(input, init) {\n  try {\n    return await fetch(input, init);\n  } catch (error) {\n    if (proxyFailureFor(error).isTimeout) throw error;\n    throw new McpProxyUpstreamError('MCP server request failed', { cause: error });\n  }\n}\n\n// Generic message surfaced to the caller when a serverUrl resolves to a\n// private/reserved address. The specific blocked IP is deliberately NOT echoed\n// back: returning it turns the proxy into an address oracle (the caller could\n// enumerate internal IPs by observing which hostnames get blocked). SSRF review\n// finding — log the concrete IP server-side for debugging, tell the caller only\n// that the host is disallowed.\nconst SSRF_BLOCKED_PUBLIC_MESSAGE = 'serverUrl host is not allowed';\n\nfunction throwBlockedAddress(blockedAddress) {\n  // Server-side audit/debug log with the concrete blocked address. This is the\n  // only place the resolved internal IP appears; it never reaches the response.\n  console.error('[mcp-proxy]', {\n    event: 'mcp_proxy_ssrf_blocked',\n    ts: new Date().toISOString(),\n    blocked_address: blockedAddress,","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/api/mcp-proxy.ts#L253-L289","documentation":"fetchMcpUpstream wraps the proxy's upstream fetch and converts network-level rejections into McpProxyUpstreamError('MCP server request failed', { cause }). Timeouts are rethrown as-is (isTimeout check) so timeout handling stays distinct; everything else — DNS failure, connection refused, TLS error, abort mid-connect — is wrapped with a generic message.","triggerScenarios":"POST/GET through /api/mcp-proxy where the configured serverUrl host is unreachable: wrong port, server down, TLS misconfiguration, IPv6-only host on IPv4 network, or the connection resets during the request. Inspect error.cause for the underlying reason.","commonSituations":"MCP server not running or crashed; serverUrl pointing at localhost from a deployed edge function; firewall blocking egress; self-signed/expired certificates.","solutions":["Check the error.cause to identify the root cause (ECONNREFUSED, ENOTFOUND, TLS alert, etc.)","Verify the MCP server is running and reachable at the configured serverUrl/port from the proxy's network","Test with curl from the same network; fix DNS, firewall, or TLS configuration","If it is a timeout, handle it via the timeout path (the original error is preserved)"],"exampleFix":"// before\nconst upstream = await fetchMcpUpstream(url, init); // throws opaque McpProxyUpstreamError\n// after\ntry { return await fetchMcpUpstream(url, init); }\ncatch (e) { if (e instanceof McpProxyUpstreamError) log.error('mcp upstream', e.cause); throw e; }","handlingStrategy":"try-catch","validationCode":"// before configuring the proxy\nconst u = new URL(serverUrl); if (u.protocol !== 'https:' && u.hostname !== 'localhost') throw new Error('https required for remote MCP servers');","typeGuard":"null","tryCatchPattern":"try { return await fetchMcpUpstream(url, init); } catch (e) { if (e instanceof McpProxyUpstreamError) { log('mcp upstream failed', { cause: e.cause }); return new Response(JSON.stringify({ error: 'upstream_unreachable' }), { status: 502 }); } throw e; }","preventionTips":["Health-check the MCP server URL at registration time","Log e.cause — the wrapper message is intentionally generic","Verify the MCP server is reachable from the proxy's network (edge != localhost)","Use TLS-valid certificates; self-signed certs surface here"],"tags":["network","proxy","mcp","connection"],"backgroundTag":"network-request-failed","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}