diff --git a/api/server/controllers/agents/client.js b/api/server/controllers/agents/client.js index bd16522c5f..d812285747 100644 --- a/api/server/controllers/agents/client.js +++ b/api/server/controllers/agents/client.js @@ -7,11 +7,12 @@ const { createRun, Tokenizer, checkAccess, + logAxiosError, resolveHeaders, getBalanceConfig, - getTransactionsConfig, memoryInstructions, formatContentStrings, + getTransactionsConfig, createMemoryProcessor, } = require('@librechat/api'); const { @@ -88,11 +89,10 @@ function createTokenCounter(encoding) { } function logToolError(graph, error, toolId) { - logger.error( - '[api/server/controllers/agents/client.js #chatCompletion] Tool Error', + logAxiosError({ error, - toolId, - ); + message: `[api/server/controllers/agents/client.js #chatCompletion] Tool Error "${toolId}"`, + }); } class AgentClient extends BaseClient { diff --git a/packages/api/src/mcp/MCPManager.ts b/packages/api/src/mcp/MCPManager.ts index 485e6882e6..f0a86113d0 100644 --- a/packages/api/src/mcp/MCPManager.ts +++ b/packages/api/src/mcp/MCPManager.ts @@ -280,6 +280,7 @@ Please follow these instructions when using tools from the respective MCP server CallToolResultSchema, { timeout: connection.timeout, + resetTimeoutOnProgress: true, ...options, }, ); diff --git a/packages/api/src/mcp/connection.ts b/packages/api/src/mcp/connection.ts index 50bed7c6d9..d937efa054 100644 --- a/packages/api/src/mcp/connection.ts +++ b/packages/api/src/mcp/connection.ts @@ -1,4 +1,5 @@ import { EventEmitter } from 'events'; +import { fetch as undiciFetch, Agent } from 'undici'; import { StdioClientTransport, getDefaultEnvironment, @@ -11,10 +12,17 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { logger } from '@librechat/data-schemas'; import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; +import type { + RequestInit as UndiciRequestInit, + RequestInfo as UndiciRequestInfo, + Response as UndiciResponse, +} from 'undici'; import type { MCPOAuthTokens } from './oauth/types'; import { mcpConfig } from './mcpConfig'; import type * as t from './types'; +type FetchLike = (url: string | URL, init?: RequestInit) => Promise; + function isStdioOptions(options: t.MCPOptions): options is t.StdioOptions { return 'command' in options; } @@ -141,11 +149,18 @@ export class MCPConnection extends EventEmitter { */ private createFetchFunction( getHeaders: () => Record | null | undefined, - ): (input: RequestInfo | URL, init?: RequestInit) => Promise { - return function customFetch(input: RequestInfo | URL, init?: RequestInit): Promise { + ): (input: UndiciRequestInfo, init?: UndiciRequestInit) => Promise { + return function customFetch( + input: UndiciRequestInfo, + init?: UndiciRequestInit, + ): Promise { const requestHeaders = getHeaders(); + const agent = new Agent({ + bodyTimeout: 0, + headersTimeout: 0, + }); if (!requestHeaders) { - return fetch(input, init); + return undiciFetch(input, { ...init, dispatcher: agent }); } let initHeaders: Record = {}; @@ -159,12 +174,13 @@ export class MCPConnection extends EventEmitter { } } - return fetch(input, { + return undiciFetch(input, { ...init, headers: { ...initHeaders, ...requestHeaders, }, + dispatcher: agent, }); }; } @@ -235,13 +251,20 @@ export class MCPConnection extends EventEmitter { eventSourceInit: { fetch: (url, init) => { const fetchHeaders = new Headers(Object.assign({}, init?.headers, headers)); - return fetch(url, { + const agent = new Agent({ + bodyTimeout: 0, + headersTimeout: 0, + }); + return undiciFetch(url, { ...init, + dispatcher: agent, headers: fetchHeaders, }); }, }, - fetch: this.createFetchFunction(this.getRequestHeaders.bind(this)), + fetch: this.createFetchFunction( + this.getRequestHeaders.bind(this), + ) as unknown as FetchLike, }); transport.onclose = () => { @@ -279,7 +302,9 @@ export class MCPConnection extends EventEmitter { headers, signal: abortController.signal, }, - fetch: this.createFetchFunction(this.getRequestHeaders.bind(this)), + fetch: this.createFetchFunction( + this.getRequestHeaders.bind(this), + ) as unknown as FetchLike, }); transport.onclose = () => {