koala73/worldmonitor · error · McpProxyUpstreamError

tools/call failed: HTTP

Error message

tools/call failed: HTTP ${callResp.status}

What it means

Thrown by mcpCallTool when any request in the tools/call flow — initialize, the call itself, or session setup — received a non-2xx HTTP status from the MCP server. The remote endpoint answered but refused the request at the HTTP layer, so the tool call could not complete.

Solutions

  1. Inspect the HTTP status in the message to distinguish auth (401/403), routing (404), and upstream (5xx) causes
  2. Verify serverUrl and any required custom headers for the MCP server
  3. Retry transient 5xx statuses once; restart the session for 404 caused by an expired session id
Defensive patterns

Strategy: retry

When it happens

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

Common situations: See trigger scenarios.


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-15). Data as JSON: /api/errors/b1a98fa04d37c686. Report an issue: GitHub.

Appendix: source

Thrown at api/mcp-proxy.ts:606

  const listData = await parseJsonRpcResponse(listResp);
  if (listData.error) throw new McpProxyUpstreamError('tools/list error: MCP server rejected request');
  return listData.result?.tools || [];
}

async function mcpCallTool(serverUrl, toolName, toolArgs, customHeaders) {
  const { response: initResp, url: sessionUrl, headers } = await postJson(
    serverUrl, buildInitPayload(), buildHeaders(customHeaders), null,
  );
  if (!initResp.ok) throw new McpProxyUpstreamError(`Initialize failed: HTTP ${initResp.status}`);
  const sessionId = initResp.headers.get('Mcp-Session-Id') || initResp.headers.get('mcp-session-id');
  const initData = await parseJsonRpcResponse(initResp);
  if (initData.error) throw new McpProxyUpstreamError('Initialize error: MCP server rejected request');
  await sendInitialized(sessionUrl, headers, sessionId);
  const { response: callResp } = await postJson(sessionUrl, {
    jsonrpc: '2.0', id: 3, method: 'tools/call',
    params: { name: toolName, arguments: toolArgs || {} },
  }, headers, sessionId);
  if (!callResp.ok) throw new McpProxyUpstreamError(`tools/call failed: HTTP ${callResp.status}`);
  const callData = await parseJsonRpcResponse(callResp);
  if (callData.error) throw new McpProxyUpstreamError('tools/call error: MCP server rejected request');
  return callData.result;
}

// --- SSE transport (HTTP+SSE, older MCP spec) ---
// Servers whose URL path ends with /sse use this protocol:
//   1. Client GETs the SSE URL — server opens a stream and emits an `endpoint` event
//      containing the URL where the client should POST JSON-RPC messages.
//   2. Client POSTs JSON-RPC to that endpoint URL.
//   3. Server sends responses on the same SSE stream as `data:` lines.

function isSseTransport(url) {
  const p = url.pathname;
  return p === '/sse' || p.endsWith('/sse');
}

function makeDeferred() {

View on GitHub (pinned to e586b8b4b8)