🚌 fix: MCP Runtime Errors while Initializing (#9046)

* chore: Remove eslint-plugin-perfectionist from dependencies

* 🚌 fix: MCP Runtime Errors while Initializing

* chore: Bump @librechat/api version to 1.3.1

* chore: import order

* chore: import order
This commit is contained in:
Danny Avila 2025-08-13 14:41:38 -04:00 committed by GitHub
parent 3eb6debe6a
commit e6cebdf2b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 52 additions and 112 deletions

View file

@ -113,20 +113,26 @@ const getAvailableTools = async (req, res) => {
return;
}
// If not in cache, build from manifest
let pluginManifest = availableTools;
if (customConfig?.mcpServers != null) {
const mcpManager = getMCPManager();
const flowsCache = getLogStores(CacheKeys.FLOWS);
const flowManager = flowsCache ? getFlowStateManager(flowsCache) : null;
const serverToolsCallback = createServerToolsCallback();
const getServerTools = createGetServerTools();
const mcpTools = await mcpManager.loadManifestTools({
flowManager,
serverToolsCallback,
getServerTools,
});
pluginManifest = [...mcpTools, ...pluginManifest];
try {
const mcpManager = getMCPManager();
const flowsCache = getLogStores(CacheKeys.FLOWS);
const flowManager = flowsCache ? getFlowStateManager(flowsCache) : null;
const serverToolsCallback = createServerToolsCallback();
const getServerTools = createGetServerTools();
const mcpTools = await mcpManager.loadManifestTools({
flowManager,
serverToolsCallback,
getServerTools,
});
pluginManifest = [...mcpTools, ...pluginManifest];
} catch (error) {
logger.error(
'[getAvailableTools] Error loading MCP Tools, servers may still be initializing:',
error,
);
}
}
/** @type {TPlugin[]} */

View file

@ -109,10 +109,10 @@ router.get('/', async function (req, res) {
for (const serverName in config.mcpServers) {
const serverConfig = config.mcpServers[serverName];
payload.mcpServers[serverName] = {
customUserVars: serverConfig?.customUserVars || {},
chatMenu: serverConfig?.chatMenu,
isOAuth: oauthServers.has(serverName),
startup: serverConfig?.startup,
chatMenu: serverConfig?.chatMenu,
isOAuth: oauthServers?.has(serverName),
customUserVars: serverConfig?.customUserVars || {},
};
}
}

View file

@ -1,15 +1,21 @@
const { z } = require('zod');
const { tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const { Time, CacheKeys, StepTypes } = require('librechat-data-provider');
const { Constants: AgentConstants, Providers, GraphEvents } = require('@librechat/agents');
const { Constants, ContentTypes, isAssistantsEndpoint } = require('librechat-data-provider');
const {
sendEvent,
MCPOAuthHandler,
normalizeServerName,
convertWithResolvedRefs,
} = require('@librechat/api');
const {
Time,
CacheKeys,
StepTypes,
Constants,
ContentTypes,
isAssistantsEndpoint,
} = require('librechat-data-provider');
const { findToken, createToken, updateToken } = require('~/models');
const { getMCPManager, getFlowStateManager } = require('~/config');
const { getCachedTools, loadCustomConfig } = require('./Config');
@ -254,15 +260,21 @@ async function getMCPSetupData(userId) {
}
const mcpManager = getMCPManager(userId);
const appConnections = mcpManager.getAllConnections() || new Map();
/** @type {ReturnType<MCPManager['getAllConnections']>} */
let appConnections = new Map();
try {
appConnections = (await mcpManager.getAllConnections()) || new Map();
} catch (error) {
logger.error(`[MCP][User: ${userId}] Error getting app connections:`, error);
}
const userConnections = mcpManager.getUserConnections(userId) || new Map();
const oauthServers = mcpManager.getOAuthServers() || new Set();
return {
mcpConfig,
oauthServers,
appConnections,
userConnections,
oauthServers,
};
}

View file

@ -14,7 +14,7 @@ async function initializeMCPs(app) {
return;
}
// Filter out servers with startup: false
/** Servers filtered with `startup: false` */
const filteredServers = {};
for (const [name, config] of Object.entries(mcpServers)) {
if (config.startup === false) {
@ -41,7 +41,7 @@ async function initializeMCPs(app) {
return;
}
const mcpTools = mcpManager.getAppToolFunctions();
const mcpTools = mcpManager.getAppToolFunctions() ?? {};
await setCachedTools({ ...cachedTools, ...mcpTools }, { isGlobal: true });
const cache = getLogStores(CacheKeys.CONFIG_STORE);

View file

@ -2,7 +2,6 @@ import { fileURLToPath } from 'node:url';
import path from 'node:path';
import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin';
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
import perfectionist from 'eslint-plugin-perfectionist';
import reactHooks from 'eslint-plugin-react-hooks';
import tsParser from '@typescript-eslint/parser';
import importPlugin from 'eslint-plugin-import';
@ -62,7 +61,6 @@ export default [
'jsx-a11y': fixupPluginRules(jsxA11Y),
'import/parsers': tsParser,
i18next,
perfectionist,
prettier: fixupPluginRules(prettier),
},
@ -139,46 +137,6 @@ export default [
'no-restricted-syntax': 'off',
'react/prop-types': 'off',
'react/display-name': 'off',
'perfectionist/sort-imports': [
'error',
{
type: 'line-length',
order: 'desc',
newlinesBetween: 'never',
customGroups: {
value: {
react: ['^react$'],
local: ['^(\\.{1,2}|~)/', '^librechat-data-provider'],
},
},
groups: [
'react',
'builtin',
'external',
['builtin-type', 'external-type'],
['internal-type'],
'local',
['parent', 'sibling', 'index'],
'object',
'unknown',
],
},
],
// 'perfectionist/sort-named-imports': [
// 'error',
// {
// type: 'line-length',
// order: 'asc',
// ignoreAlias: false,
// ignoreCase: true,
// specialCharacters: 'keep',
// groupKind: 'mixed',
// partitionByNewLine: false,
// partitionByComment: false,
// },
// ],
},
},
{

31
package-lock.json generated
View file

@ -30,7 +30,6 @@
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-perfectionist": "^4.8.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
@ -33994,24 +33993,6 @@
"node": ">= 0.4"
}
},
"node_modules/eslint-plugin-perfectionist": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.8.0.tgz",
"integrity": "sha512-ZF04IAPGItYMlj9xjgvvl/QpksZf79g0dkxbNcuxDjbcUSZ4CwucJ7h5Yzt5JuHe+i6igQbUYEp40j4ndfbvWQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "^8.23.0",
"@typescript-eslint/utils": "^8.23.0",
"natural-orderby": "^5.0.0"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"peerDependencies": {
"eslint": ">=8.0.0"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
@ -41452,16 +41433,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/natural-orderby": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz",
"integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -51345,7 +51316,7 @@
},
"packages/api": {
"name": "@librechat/api",
"version": "1.3.0",
"version": "1.3.1",
"license": "ISC",
"devDependencies": {
"@babel/preset-env": "^7.21.5",

View file

@ -102,7 +102,6 @@
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-perfectionist": "^4.8.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",

View file

@ -1,6 +1,6 @@
{
"name": "@librechat/api",
"version": "1.3.0",
"version": "1.3.1",
"type": "commonjs",
"description": "MCP services for LibreChat",
"main": "dist/index.js",

View file

@ -5,10 +5,10 @@ import type { TUser } from 'librechat-data-provider';
import type { MCPOAuthTokens, MCPOAuthFlowMetadata } from '~/mcp/oauth';
import type { FlowStateManager } from '~/flow/manager';
import type { FlowMetadata } from '~/flow/types';
import type * as t from './types';
import { MCPTokenStorage, MCPOAuthHandler } from '~/mcp/oauth';
import { MCPConnection } from './connection';
import { processMCPEnv } from '~/utils';
import type * as t from './types';
export interface BasicConnectionOptions {
serverName: string;
@ -350,15 +350,9 @@ export class MCPConnectionFactory {
logger.info(`${this.logPrefix} OAuth flow started, issued authorization URL to user`);
await this.oauthStart(authorizationUrl);
} else {
logger.info(`
Please visit the following URL to authenticate:
${authorizationUrl}
${this.logPrefix} Flow ID: ${newFlowId}
`);
logger.info(
`${this.logPrefix} OAuth flow started, no \`oauthStart\` handler defined, relying on callback endpoint`,
);
}
/** Tokens from the new flow */

View file

@ -1,17 +1,17 @@
import { CallToolResultSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { logger } from '@librechat/data-schemas';
import pick from 'lodash/pick';
import { logger } from '@librechat/data-schemas';
import { CallToolResultSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
import type { TokenMethods } from '@librechat/data-schemas';
import type { TUser } from 'librechat-data-provider';
import type { FlowStateManager } from '~/flow/manager';
import type { TUser } from 'librechat-data-provider';
import type { MCPOAuthTokens } from '~/mcp/oauth';
import type * as t from './types';
import { UserConnectionManager } from '~/mcp/UserConnectionManager';
import { ConnectionsRepository } from '~/mcp/ConnectionsRepository';
import { formatToolContent } from './parsers';
import { MCPConnection } from './connection';
import { CONSTANTS } from './enum';
import type * as t from './types';
/**
* Centralized manager for MCP server connections and tool execution.
@ -43,17 +43,17 @@ export class MCPManager extends UserConnectionManager {
}
/** Returns all app-level connections */
public async getAllConnections(): Promise<Map<string, MCPConnection>> {
public async getAllConnections(): Promise<Map<string, MCPConnection> | null> {
return this.appConnections!.getAll();
}
/** Get servers that require OAuth */
public getOAuthServers(): Set<string> {
public getOAuthServers(): Set<string> | null {
return this.serversRegistry.oauthServers!;
}
/** Returns all available tool functions from app-level connections */
public getAppToolFunctions(): t.LCAvailableTools {
public getAppToolFunctions(): t.LCAvailableTools | null {
return this.serversRegistry.toolFunctions!;
}