danny-avila/LibreChat · error · Error

[MCP][${serverName}][${toolName}] tool call failed${error?.m

Error message

[MCP][${serverName}][${toolName}] tool call failed${error?.message ? `: ${error?.message}` : '.'}

What it means

The MCP tool _call catch-all (MCP.js:1153) rethrows with this message when the caught error is neither an OAuth-class error nor recoverable — it appends the upstream error.message if present. It is the generic surface for any MCP tool call failure: transport errors, server-side execution failures, malformed tool arguments, timeouts, aborts.

Source

Thrown at api/server/services/MCP.js:1153

        error.message === 'OAuth flow initiated - return early' ||
        error.message === 'Pending OAuth flow reused - return early';

      if (isOAuthError) {
        if (
          capturedServerConfig &&
          !requiresOAuthMachinery(capturedServerConfig) &&
          !isOAuthFlowSignal
        ) {
          throw new Error(
            `[MCP][${serverName}][${toolName}] upstream authentication failed; MCP OAuth is not configured for this server.`,
          );
        }
        throw new Error(
          `[MCP][${serverName}][${toolName}] OAuth authentication required. Please check the server logs for the authentication URL.`,
        );
      }

      throw new Error(
        `[MCP][${serverName}][${toolName}] tool call failed${error?.message ? `: ${error?.message}` : '.'}`,
      );
    }
  };

  const toolInstance = tool(_call, {
    schema,
    name: normalizedToolKey,
    description: description || '',
    responseFormat: AgentConstants.CONTENT_AND_ARTIFACT,
  });
  toolInstance.mcp = true;
  toolInstance.mcpRawServerName = serverName;
  // Ephemeral request-scoped servers (runtime body placeholders) tear their
  // connection down at request end, so they must never be backgrounded. A
  // missing/stale config means the server's lifetime is unknowable, so fail
  // closed (foreground) rather than risk a detached call against a torn-down
  // connection.

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Read the appended error.message — it is the upstream's own failure reason and is the primary diagnostic.
  2. If transient (timeout/reset), retry the call; if the server is remote, check connectivity.
  3. Validate the tool arguments against the server's current schema; update the call if the server changed.
  4. If an AbortSignal is being passed, ensure it is not being cancelled prematurely upstream.
Defensive patterns

Strategy: try-catch

Validate before calling

function assertToolArgs(schema, args) {
  for (const [k, t] of Object.entries(schema)) {
    if (typeof args?.[k] !== t) throw new Error(`arg ${k} expected ${t}`);
  }
}

Try / catch

try {
  return await callMcpTool(...);
} catch (e) {
  if (/timeout|reset|ECONNRESET|429|503/.test(e.message)) { await backoff(); return retry(); }
  throw e;
}

Prevention

When it happens

Trigger: mcpManager.callTool rejects for any non-auth reason: the MCP server returned a non-401 error, the SSE/stdio transport died, the tool arguments failed server-side validation, an AbortSignal fired, or the server threw during execution.

Common situations: Network outage to a remote MCP server. A tool whose arguments changed upstream. Long-running tool hit the request timeout. Server restarted mid-call. Schema mismatch after an MCP server upgrade.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/9d5be58192613616. Report an issue: GitHub.