mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 08:20:14 +01:00
🚌 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:
parent
3eb6debe6a
commit
e6cebdf2b6
10 changed files with 52 additions and 112 deletions
|
|
@ -113,20 +113,26 @@ const getAvailableTools = async (req, res) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not in cache, build from manifest
|
|
||||||
let pluginManifest = availableTools;
|
let pluginManifest = availableTools;
|
||||||
if (customConfig?.mcpServers != null) {
|
if (customConfig?.mcpServers != null) {
|
||||||
const mcpManager = getMCPManager();
|
try {
|
||||||
const flowsCache = getLogStores(CacheKeys.FLOWS);
|
const mcpManager = getMCPManager();
|
||||||
const flowManager = flowsCache ? getFlowStateManager(flowsCache) : null;
|
const flowsCache = getLogStores(CacheKeys.FLOWS);
|
||||||
const serverToolsCallback = createServerToolsCallback();
|
const flowManager = flowsCache ? getFlowStateManager(flowsCache) : null;
|
||||||
const getServerTools = createGetServerTools();
|
const serverToolsCallback = createServerToolsCallback();
|
||||||
const mcpTools = await mcpManager.loadManifestTools({
|
const getServerTools = createGetServerTools();
|
||||||
flowManager,
|
const mcpTools = await mcpManager.loadManifestTools({
|
||||||
serverToolsCallback,
|
flowManager,
|
||||||
getServerTools,
|
serverToolsCallback,
|
||||||
});
|
getServerTools,
|
||||||
pluginManifest = [...mcpTools, ...pluginManifest];
|
});
|
||||||
|
pluginManifest = [...mcpTools, ...pluginManifest];
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
'[getAvailableTools] Error loading MCP Tools, servers may still be initializing:',
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {TPlugin[]} */
|
/** @type {TPlugin[]} */
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,10 @@ router.get('/', async function (req, res) {
|
||||||
for (const serverName in config.mcpServers) {
|
for (const serverName in config.mcpServers) {
|
||||||
const serverConfig = config.mcpServers[serverName];
|
const serverConfig = config.mcpServers[serverName];
|
||||||
payload.mcpServers[serverName] = {
|
payload.mcpServers[serverName] = {
|
||||||
customUserVars: serverConfig?.customUserVars || {},
|
|
||||||
chatMenu: serverConfig?.chatMenu,
|
|
||||||
isOAuth: oauthServers.has(serverName),
|
|
||||||
startup: serverConfig?.startup,
|
startup: serverConfig?.startup,
|
||||||
|
chatMenu: serverConfig?.chatMenu,
|
||||||
|
isOAuth: oauthServers?.has(serverName),
|
||||||
|
customUserVars: serverConfig?.customUserVars || {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
const { z } = require('zod');
|
const { z } = require('zod');
|
||||||
const { tool } = require('@langchain/core/tools');
|
const { tool } = require('@langchain/core/tools');
|
||||||
const { logger } = require('@librechat/data-schemas');
|
const { logger } = require('@librechat/data-schemas');
|
||||||
const { Time, CacheKeys, StepTypes } = require('librechat-data-provider');
|
|
||||||
const { Constants: AgentConstants, Providers, GraphEvents } = require('@librechat/agents');
|
const { Constants: AgentConstants, Providers, GraphEvents } = require('@librechat/agents');
|
||||||
const { Constants, ContentTypes, isAssistantsEndpoint } = require('librechat-data-provider');
|
|
||||||
const {
|
const {
|
||||||
sendEvent,
|
sendEvent,
|
||||||
MCPOAuthHandler,
|
MCPOAuthHandler,
|
||||||
normalizeServerName,
|
normalizeServerName,
|
||||||
convertWithResolvedRefs,
|
convertWithResolvedRefs,
|
||||||
} = require('@librechat/api');
|
} = require('@librechat/api');
|
||||||
|
const {
|
||||||
|
Time,
|
||||||
|
CacheKeys,
|
||||||
|
StepTypes,
|
||||||
|
Constants,
|
||||||
|
ContentTypes,
|
||||||
|
isAssistantsEndpoint,
|
||||||
|
} = require('librechat-data-provider');
|
||||||
const { findToken, createToken, updateToken } = require('~/models');
|
const { findToken, createToken, updateToken } = require('~/models');
|
||||||
const { getMCPManager, getFlowStateManager } = require('~/config');
|
const { getMCPManager, getFlowStateManager } = require('~/config');
|
||||||
const { getCachedTools, loadCustomConfig } = require('./Config');
|
const { getCachedTools, loadCustomConfig } = require('./Config');
|
||||||
|
|
@ -254,15 +260,21 @@ async function getMCPSetupData(userId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mcpManager = getMCPManager(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 userConnections = mcpManager.getUserConnections(userId) || new Map();
|
||||||
const oauthServers = mcpManager.getOAuthServers() || new Set();
|
const oauthServers = mcpManager.getOAuthServers() || new Set();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mcpConfig,
|
mcpConfig,
|
||||||
|
oauthServers,
|
||||||
appConnections,
|
appConnections,
|
||||||
userConnections,
|
userConnections,
|
||||||
oauthServers,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ async function initializeMCPs(app) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out servers with startup: false
|
/** Servers filtered with `startup: false` */
|
||||||
const filteredServers = {};
|
const filteredServers = {};
|
||||||
for (const [name, config] of Object.entries(mcpServers)) {
|
for (const [name, config] of Object.entries(mcpServers)) {
|
||||||
if (config.startup === false) {
|
if (config.startup === false) {
|
||||||
|
|
@ -41,7 +41,7 @@ async function initializeMCPs(app) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mcpTools = mcpManager.getAppToolFunctions();
|
const mcpTools = mcpManager.getAppToolFunctions() ?? {};
|
||||||
await setCachedTools({ ...cachedTools, ...mcpTools }, { isGlobal: true });
|
await setCachedTools({ ...cachedTools, ...mcpTools }, { isGlobal: true });
|
||||||
|
|
||||||
const cache = getLogStores(CacheKeys.CONFIG_STORE);
|
const cache = getLogStores(CacheKeys.CONFIG_STORE);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { fileURLToPath } from 'node:url';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin';
|
import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin';
|
||||||
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
|
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
|
||||||
import perfectionist from 'eslint-plugin-perfectionist';
|
|
||||||
import reactHooks from 'eslint-plugin-react-hooks';
|
import reactHooks from 'eslint-plugin-react-hooks';
|
||||||
import tsParser from '@typescript-eslint/parser';
|
import tsParser from '@typescript-eslint/parser';
|
||||||
import importPlugin from 'eslint-plugin-import';
|
import importPlugin from 'eslint-plugin-import';
|
||||||
|
|
@ -62,7 +61,6 @@ export default [
|
||||||
'jsx-a11y': fixupPluginRules(jsxA11Y),
|
'jsx-a11y': fixupPluginRules(jsxA11Y),
|
||||||
'import/parsers': tsParser,
|
'import/parsers': tsParser,
|
||||||
i18next,
|
i18next,
|
||||||
perfectionist,
|
|
||||||
prettier: fixupPluginRules(prettier),
|
prettier: fixupPluginRules(prettier),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -139,46 +137,6 @@ export default [
|
||||||
'no-restricted-syntax': 'off',
|
'no-restricted-syntax': 'off',
|
||||||
'react/prop-types': 'off',
|
'react/prop-types': 'off',
|
||||||
'react/display-name': '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
31
package-lock.json
generated
|
|
@ -30,7 +30,6 @@
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"eslint-plugin-jest": "^28.11.0",
|
"eslint-plugin-jest": "^28.11.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-perfectionist": "^4.8.0",
|
|
||||||
"eslint-plugin-prettier": "^5.2.3",
|
"eslint-plugin-prettier": "^5.2.3",
|
||||||
"eslint-plugin-react": "^7.37.4",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
|
|
@ -33994,24 +33993,6 @@
|
||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/eslint-plugin-prettier": {
|
||||||
"version": "5.2.3",
|
"version": "5.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
|
||||||
|
|
@ -41452,16 +41433,6 @@
|
||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
|
|
@ -51345,7 +51316,7 @@
|
||||||
},
|
},
|
||||||
"packages/api": {
|
"packages/api": {
|
||||||
"name": "@librechat/api",
|
"name": "@librechat/api",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "^7.21.5",
|
"@babel/preset-env": "^7.21.5",
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"eslint-plugin-jest": "^28.11.0",
|
"eslint-plugin-jest": "^28.11.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-perfectionist": "^4.8.0",
|
|
||||||
"eslint-plugin-prettier": "^5.2.3",
|
"eslint-plugin-prettier": "^5.2.3",
|
||||||
"eslint-plugin-react": "^7.37.4",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@librechat/api",
|
"name": "@librechat/api",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"description": "MCP services for LibreChat",
|
"description": "MCP services for LibreChat",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ import type { TUser } from 'librechat-data-provider';
|
||||||
import type { MCPOAuthTokens, MCPOAuthFlowMetadata } from '~/mcp/oauth';
|
import type { MCPOAuthTokens, MCPOAuthFlowMetadata } from '~/mcp/oauth';
|
||||||
import type { FlowStateManager } from '~/flow/manager';
|
import type { FlowStateManager } from '~/flow/manager';
|
||||||
import type { FlowMetadata } from '~/flow/types';
|
import type { FlowMetadata } from '~/flow/types';
|
||||||
|
import type * as t from './types';
|
||||||
import { MCPTokenStorage, MCPOAuthHandler } from '~/mcp/oauth';
|
import { MCPTokenStorage, MCPOAuthHandler } from '~/mcp/oauth';
|
||||||
import { MCPConnection } from './connection';
|
import { MCPConnection } from './connection';
|
||||||
import { processMCPEnv } from '~/utils';
|
import { processMCPEnv } from '~/utils';
|
||||||
import type * as t from './types';
|
|
||||||
|
|
||||||
export interface BasicConnectionOptions {
|
export interface BasicConnectionOptions {
|
||||||
serverName: string;
|
serverName: string;
|
||||||
|
|
@ -350,15 +350,9 @@ export class MCPConnectionFactory {
|
||||||
logger.info(`${this.logPrefix} OAuth flow started, issued authorization URL to user`);
|
logger.info(`${this.logPrefix} OAuth flow started, issued authorization URL to user`);
|
||||||
await this.oauthStart(authorizationUrl);
|
await this.oauthStart(authorizationUrl);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`
|
logger.info(
|
||||||
═══════════════════════════════════════════════════════════════════════
|
`${this.logPrefix} OAuth flow started, no \`oauthStart\` handler defined, relying on callback endpoint`,
|
||||||
Please visit the following URL to authenticate:
|
);
|
||||||
|
|
||||||
${authorizationUrl}
|
|
||||||
|
|
||||||
${this.logPrefix} Flow ID: ${newFlowId}
|
|
||||||
═══════════════════════════════════════════════════════════════════════
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tokens from the new flow */
|
/** Tokens from the new flow */
|
||||||
|
|
|
||||||
|
|
@ -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 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 { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
||||||
import type { TokenMethods } from '@librechat/data-schemas';
|
import type { TokenMethods } from '@librechat/data-schemas';
|
||||||
import type { TUser } from 'librechat-data-provider';
|
|
||||||
import type { FlowStateManager } from '~/flow/manager';
|
import type { FlowStateManager } from '~/flow/manager';
|
||||||
|
import type { TUser } from 'librechat-data-provider';
|
||||||
import type { MCPOAuthTokens } from '~/mcp/oauth';
|
import type { MCPOAuthTokens } from '~/mcp/oauth';
|
||||||
|
import type * as t from './types';
|
||||||
import { UserConnectionManager } from '~/mcp/UserConnectionManager';
|
import { UserConnectionManager } from '~/mcp/UserConnectionManager';
|
||||||
import { ConnectionsRepository } from '~/mcp/ConnectionsRepository';
|
import { ConnectionsRepository } from '~/mcp/ConnectionsRepository';
|
||||||
import { formatToolContent } from './parsers';
|
import { formatToolContent } from './parsers';
|
||||||
import { MCPConnection } from './connection';
|
import { MCPConnection } from './connection';
|
||||||
import { CONSTANTS } from './enum';
|
import { CONSTANTS } from './enum';
|
||||||
import type * as t from './types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Centralized manager for MCP server connections and tool execution.
|
* Centralized manager for MCP server connections and tool execution.
|
||||||
|
|
@ -43,17 +43,17 @@ export class MCPManager extends UserConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns all app-level connections */
|
/** Returns all app-level connections */
|
||||||
public async getAllConnections(): Promise<Map<string, MCPConnection>> {
|
public async getAllConnections(): Promise<Map<string, MCPConnection> | null> {
|
||||||
return this.appConnections!.getAll();
|
return this.appConnections!.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get servers that require OAuth */
|
/** Get servers that require OAuth */
|
||||||
public getOAuthServers(): Set<string> {
|
public getOAuthServers(): Set<string> | null {
|
||||||
return this.serversRegistry.oauthServers!;
|
return this.serversRegistry.oauthServers!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns all available tool functions from app-level connections */
|
/** Returns all available tool functions from app-level connections */
|
||||||
public getAppToolFunctions(): t.LCAvailableTools {
|
public getAppToolFunctions(): t.LCAvailableTools | null {
|
||||||
return this.serversRegistry.toolFunctions!;
|
return this.serversRegistry.toolFunctions!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue