mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🧩 refactor: Decouple MCP Config from Startup Config (#10689)
* Decouple mcp config from start up config * Chore: Work on AI Review and Copilot Comments - setRawConfig is not needed since the private raw config is not needed any more - !!serversLoading bug fixed - added unit tests for route /api/mcp/servers - copilot comments addressed * chore: remove comments * chore: rename data-provider dir for MCP * chore: reorganize mcp specific query hooks * fix: consolidate imports for MCP server manager * chore: add dev-staging branch to frontend review workflow triggers * feat: add GitHub Actions workflow for building and pushing Docker images to GitHub Container Registry and Docker Hub * fix: update label for tag input in BookmarkForm tests to improve clarity --------- Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com> Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
98b188f26c
commit
ef1b7f0157
36 changed files with 548 additions and 301 deletions
|
|
@ -10,6 +10,7 @@ const {
|
|||
createSafeUser,
|
||||
mcpToolPattern,
|
||||
loadWebSearchAuth,
|
||||
mcpServersRegistry,
|
||||
} = require('@librechat/api');
|
||||
const {
|
||||
Tools,
|
||||
|
|
@ -347,7 +348,7 @@ Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|new
|
|||
/** Placeholder used for UI purposes */
|
||||
continue;
|
||||
}
|
||||
if (serverName && options.req?.config?.mcpConfig?.[serverName] == null) {
|
||||
if (serverName && (await mcpServersRegistry.getServerConfig(serverName, user)) == undefined) {
|
||||
logger.warn(
|
||||
`MCP server "${serverName}" for "${toolName}" tool is not configured${agent?.id != null && agent.id ? ` but attached to "${agent.id}"` : ''}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,7 @@
|
|||
*/
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Constants } = require('librechat-data-provider');
|
||||
const {
|
||||
cacheMCPServerTools,
|
||||
getMCPServerTools,
|
||||
getAppConfig,
|
||||
} = require('~/server/services/Config');
|
||||
const { cacheMCPServerTools, getMCPServerTools } = require('~/server/services/Config');
|
||||
const { getMCPManager } = require('~/config');
|
||||
const { mcpServersRegistry } = require('@librechat/api');
|
||||
|
||||
|
|
@ -23,13 +19,14 @@ const getMCPTools = async (req, res) => {
|
|||
return res.status(401).json({ message: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));
|
||||
if (!appConfig?.mcpConfig) {
|
||||
const mcpConfig = await mcpServersRegistry.getAllServerConfigs(userId);
|
||||
const configuredServers = mcpConfig ? Object.keys(mcpConfig) : [];
|
||||
|
||||
if (!mcpConfig || Object.keys(mcpConfig).length == 0) {
|
||||
return res.status(200).json({ servers: {} });
|
||||
}
|
||||
|
||||
const mcpManager = getMCPManager();
|
||||
const configuredServers = Object.keys(appConfig.mcpConfig);
|
||||
const mcpServers = {};
|
||||
|
||||
const cachePromises = configuredServers.map((serverName) =>
|
||||
|
|
@ -71,7 +68,7 @@ const getMCPTools = async (req, res) => {
|
|||
const serverTools = serverToolsMap.get(serverName);
|
||||
|
||||
// Get server config once
|
||||
const serverConfig = appConfig.mcpConfig[serverName];
|
||||
const serverConfig = mcpConfig[serverName];
|
||||
const rawServerConfig = await mcpServersRegistry.getServerConfig(serverName, userId);
|
||||
|
||||
// Initialize server object with all server-level data
|
||||
|
|
@ -127,7 +124,29 @@ const getMCPTools = async (req, res) => {
|
|||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Get all MCP servers with permissions
|
||||
* @route GET /api/mcp/servers
|
||||
*/
|
||||
const getMCPServersList = async (req, res) => {
|
||||
try {
|
||||
const userId = req.user?.id;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ message: 'Unauthorized' });
|
||||
}
|
||||
// TODO - Ensure DB servers loaded into registry (configs only)
|
||||
|
||||
// 2. Get all server configs from registry (YAML + DB)
|
||||
const serverConfigs = await mcpServersRegistry.getAllServerConfigs(userId);
|
||||
|
||||
return res.json(serverConfigs);
|
||||
} catch (error) {
|
||||
logger.error('[getMCPServersList]', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getMCPTools,
|
||||
getMCPServersList,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ jest.mock('@librechat/api', () => ({
|
|||
mcpServersRegistry: {
|
||||
getServerConfig: jest.fn(),
|
||||
getOAuthServers: jest.fn(),
|
||||
getAllServerConfigs: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
@ -1415,4 +1416,62 @@ describe('MCP Routes', () => {
|
|||
expect(response.headers.location).toContain('/oauth/success');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /servers', () => {
|
||||
const { mcpServersRegistry } = require('@librechat/api');
|
||||
|
||||
it('should return all server configs for authenticated user', async () => {
|
||||
const mockServerConfigs = {
|
||||
'server-1': {
|
||||
endpoint: 'http://server1.com',
|
||||
name: 'Server 1',
|
||||
},
|
||||
'server-2': {
|
||||
endpoint: 'http://server2.com',
|
||||
name: 'Server 2',
|
||||
},
|
||||
};
|
||||
|
||||
mcpServersRegistry.getAllServerConfigs.mockResolvedValue(mockServerConfigs);
|
||||
|
||||
const response = await request(app).get('/api/mcp/servers');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockServerConfigs);
|
||||
expect(mcpServersRegistry.getAllServerConfigs).toHaveBeenCalledWith('test-user-id');
|
||||
});
|
||||
|
||||
it('should return empty object when no servers are configured', async () => {
|
||||
mcpServersRegistry.getAllServerConfigs.mockResolvedValue({});
|
||||
|
||||
const response = await request(app).get('/api/mcp/servers');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({});
|
||||
});
|
||||
|
||||
it('should return 401 when user is not authenticated', async () => {
|
||||
const unauthApp = express();
|
||||
unauthApp.use(express.json());
|
||||
unauthApp.use((req, _res, next) => {
|
||||
req.user = null;
|
||||
next();
|
||||
});
|
||||
unauthApp.use('/api/mcp', mcpRouter);
|
||||
|
||||
const response = await request(unauthApp).get('/api/mcp/servers');
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
expect(response.body).toEqual({ message: 'Unauthorized' });
|
||||
});
|
||||
|
||||
it('should return 500 when server config retrieval fails', async () => {
|
||||
mcpServersRegistry.getAllServerConfigs.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app).get('/api/mcp/servers');
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.body).toEqual({ error: 'Database error' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
const express = require('express');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { isEnabled, getBalanceConfig } = require('@librechat/api');
|
||||
const {
|
||||
Constants,
|
||||
CacheKeys,
|
||||
removeNullishValues,
|
||||
defaultSocialLogins,
|
||||
} = require('librechat-data-provider');
|
||||
const { Constants, CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
|
||||
const { getLdapConfig } = require('~/server/services/Config/ldap');
|
||||
const { getAppConfig } = require('~/server/services/Config/app');
|
||||
const { getProjectByName } = require('~/models/Project');
|
||||
const { getMCPManager } = require('~/config');
|
||||
const { getLogStores } = require('~/cache');
|
||||
const { mcpServersRegistry } = require('@librechat/api');
|
||||
|
||||
const router = express.Router();
|
||||
const emailLoginEnabled =
|
||||
|
|
@ -30,46 +23,11 @@ const publicSharedLinksEnabled =
|
|||
const sharePointFilePickerEnabled = isEnabled(process.env.ENABLE_SHAREPOINT_FILEPICKER);
|
||||
const openidReuseTokens = isEnabled(process.env.OPENID_REUSE_TOKENS);
|
||||
|
||||
/**
|
||||
* Fetches MCP servers from registry and adds them to the payload.
|
||||
* Registry now includes all configured servers (from YAML) plus inspection data when available.
|
||||
* Always fetches fresh to avoid caching incomplete initialization state.
|
||||
*/
|
||||
const getMCPServers = async (payload, appConfig) => {
|
||||
try {
|
||||
if (appConfig?.mcpConfig == null) {
|
||||
return;
|
||||
}
|
||||
const mcpManager = getMCPManager();
|
||||
if (!mcpManager) {
|
||||
return;
|
||||
}
|
||||
const mcpServers = await mcpServersRegistry.getAllServerConfigs();
|
||||
if (!mcpServers) return;
|
||||
for (const serverName in mcpServers) {
|
||||
if (!payload.mcpServers) {
|
||||
payload.mcpServers = {};
|
||||
}
|
||||
const serverConfig = mcpServers[serverName];
|
||||
payload.mcpServers[serverName] = removeNullishValues({
|
||||
startup: serverConfig?.startup,
|
||||
chatMenu: serverConfig?.chatMenu,
|
||||
isOAuth: serverConfig.requiresOAuth,
|
||||
customUserVars: serverConfig?.customUserVars,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error loading MCP servers', error);
|
||||
}
|
||||
};
|
||||
|
||||
router.get('/', async function (req, res) {
|
||||
const cache = getLogStores(CacheKeys.CONFIG_STORE);
|
||||
|
||||
const cachedStartupConfig = await cache.get(CacheKeys.STARTUP_CONFIG);
|
||||
if (cachedStartupConfig) {
|
||||
const appConfig = await getAppConfig({ role: req.user?.role });
|
||||
await getMCPServers(cachedStartupConfig, appConfig);
|
||||
res.send(cachedStartupConfig);
|
||||
return;
|
||||
}
|
||||
|
|
@ -190,7 +148,6 @@ router.get('/', async function (req, res) {
|
|||
}
|
||||
|
||||
await cache.set(CacheKeys.STARTUP_CONFIG, payload);
|
||||
await getMCPServers(payload, appConfig);
|
||||
return res.status(200).send(payload);
|
||||
} catch (err) {
|
||||
logger.error('Error in startup config', err);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const { findToken, updateToken, createToken, deleteTokens } = require('~/models'
|
|||
const { getUserPluginAuthValue } = require('~/server/services/PluginService');
|
||||
const { updateMCPServerTools } = require('~/server/services/Config/mcp');
|
||||
const { reinitMCPServer } = require('~/server/services/Tools/mcp');
|
||||
const { getMCPServersList } = require('~/server/controllers/mcp');
|
||||
const { getMCPTools } = require('~/server/controllers/mcp');
|
||||
const { requireJwtAuth } = require('~/server/middleware');
|
||||
const { findPluginAuthsByKeys } = require('~/models');
|
||||
|
|
@ -428,11 +429,12 @@ router.get('/connection/status', requireJwtAuth, async (req, res) => {
|
|||
);
|
||||
const connectionStatus = {};
|
||||
|
||||
for (const [serverName] of Object.entries(mcpConfig)) {
|
||||
for (const [serverName, config] of Object.entries(mcpConfig)) {
|
||||
try {
|
||||
connectionStatus[serverName] = await getServerConnectionStatus(
|
||||
user.id,
|
||||
serverName,
|
||||
config,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -487,6 +489,7 @@ router.get('/connection/status/:serverName', requireJwtAuth, async (req, res) =>
|
|||
const serverStatus = await getServerConnectionStatus(
|
||||
user.id,
|
||||
serverName,
|
||||
mcpConfig[serverName],
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -566,5 +569,11 @@ async function getOAuthHeaders(serverName, userId) {
|
|||
const serverConfig = await mcpServersRegistry.getServerConfig(serverName, userId);
|
||||
return serverConfig?.oauth_headers ?? {};
|
||||
}
|
||||
/**
|
||||
* Get list of accessible MCP servers
|
||||
* @route GET /api/mcp/servers
|
||||
* @returns {MCPServersListResponse} 200 - Success response - application/json
|
||||
*/
|
||||
router.get('/servers', requireJwtAuth, getMCPServersList);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -435,8 +435,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
|
|||
* @returns {Object} Object containing mcpConfig, appConnections, userConnections, and oauthServers
|
||||
*/
|
||||
async function getMCPSetupData(userId) {
|
||||
const config = await getAppConfig();
|
||||
const mcpConfig = config?.mcpConfig;
|
||||
const mcpConfig = await mcpServersRegistry.getAllServerConfigs(userId);
|
||||
|
||||
if (!mcpConfig) {
|
||||
throw new Error('MCP config not found');
|
||||
|
|
@ -451,7 +450,7 @@ async function getMCPSetupData(userId) {
|
|||
logger.error(`[MCP][User: ${userId}] Error getting app connections:`, error);
|
||||
}
|
||||
const userConnections = mcpManager.getUserConnections(userId) || new Map();
|
||||
const oauthServers = await mcpServersRegistry.getOAuthServers();
|
||||
const oauthServers = await mcpServersRegistry.getOAuthServers(userId);
|
||||
|
||||
return {
|
||||
mcpConfig,
|
||||
|
|
@ -524,24 +523,26 @@ async function checkOAuthFlowStatus(userId, serverName) {
|
|||
* Get connection status for a specific MCP server
|
||||
* @param {string} userId - The user ID
|
||||
* @param {string} serverName - The server name
|
||||
* @param {Map} appConnections - App-level connections
|
||||
* @param {Map} userConnections - User-level connections
|
||||
* @param {import('@librechat/api').ParsedServerConfig} config - The server configuration
|
||||
* @param {Map<string, import('@librechat/api').MCPConnection>} appConnections - App-level connections
|
||||
* @param {Map<string, import('@librechat/api').MCPConnection>} userConnections - User-level connections
|
||||
* @param {Set} oauthServers - Set of OAuth servers
|
||||
* @returns {Object} Object containing requiresOAuth and connectionState
|
||||
*/
|
||||
async function getServerConnectionStatus(
|
||||
userId,
|
||||
serverName,
|
||||
config,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
) {
|
||||
const getConnectionState = () =>
|
||||
appConnections.get(serverName)?.connectionState ??
|
||||
userConnections.get(serverName)?.connectionState ??
|
||||
'disconnected';
|
||||
const connection = appConnections.get(serverName) || userConnections.get(serverName);
|
||||
const isStaleOrDoNotExist = connection ? connection?.isStale(config.lastUpdatedAt) : true;
|
||||
|
||||
const baseConnectionState = getConnectionState();
|
||||
const baseConnectionState = isStaleOrDoNotExist
|
||||
? 'disconnected'
|
||||
: connection?.connectionState || 'disconnected';
|
||||
let finalConnectionState = baseConnectionState;
|
||||
|
||||
// connection state overrides specific to OAuth servers
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ jest.mock('@librechat/api', () => ({
|
|||
convertWithResolvedRefs: jest.fn((params) => params),
|
||||
mcpServersRegistry: {
|
||||
getOAuthServers: jest.fn(() => Promise.resolve(new Set())),
|
||||
getAllServerConfigs: jest.fn(() => Promise.resolve({})),
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
@ -118,31 +119,28 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
describe('getMCPSetupData', () => {
|
||||
const mockUserId = 'user-123';
|
||||
const mockConfig = {
|
||||
mcpServers: {
|
||||
server1: { type: 'stdio' },
|
||||
server2: { type: 'http' },
|
||||
},
|
||||
server1: { type: 'stdio' },
|
||||
server2: { type: 'http' },
|
||||
};
|
||||
let mockGetAppConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetAppConfig = require('./Config').getAppConfig;
|
||||
mockGetMCPManager.mockReturnValue({
|
||||
appConnections: { getAll: jest.fn(() => new Map()) },
|
||||
getUserConnections: jest.fn(() => new Map()),
|
||||
});
|
||||
mockMcpServersRegistry.getOAuthServers.mockResolvedValue(new Set());
|
||||
mockMcpServersRegistry.getAllServerConfigs.mockResolvedValue(mockConfig);
|
||||
});
|
||||
|
||||
it('should successfully return MCP setup data', async () => {
|
||||
mockGetAppConfig.mockResolvedValue({ mcpConfig: mockConfig.mcpServers });
|
||||
mockMcpServersRegistry.getAllServerConfigs.mockResolvedValue(mockConfig);
|
||||
|
||||
const mockAppConnections = new Map([['server1', { status: 'connected' }]]);
|
||||
const mockUserConnections = new Map([['server2', { status: 'disconnected' }]]);
|
||||
const mockOAuthServers = new Set(['server2']);
|
||||
|
||||
const mockMCPManager = {
|
||||
appConnections: { getAll: jest.fn(() => mockAppConnections) },
|
||||
appConnections: { getAll: jest.fn(() => Promise.resolve(mockAppConnections)) },
|
||||
getUserConnections: jest.fn(() => mockUserConnections),
|
||||
};
|
||||
mockGetMCPManager.mockReturnValue(mockMCPManager);
|
||||
|
|
@ -150,14 +148,14 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
|
||||
const result = await getMCPSetupData(mockUserId);
|
||||
|
||||
expect(mockGetAppConfig).toHaveBeenCalled();
|
||||
expect(mockMcpServersRegistry.getAllServerConfigs).toHaveBeenCalledWith(mockUserId);
|
||||
expect(mockGetMCPManager).toHaveBeenCalledWith(mockUserId);
|
||||
expect(mockMCPManager.appConnections.getAll).toHaveBeenCalled();
|
||||
expect(mockMCPManager.getUserConnections).toHaveBeenCalledWith(mockUserId);
|
||||
expect(mockMcpServersRegistry.getOAuthServers).toHaveBeenCalled();
|
||||
expect(mockMcpServersRegistry.getOAuthServers).toHaveBeenCalledWith(mockUserId);
|
||||
|
||||
expect(result).toEqual({
|
||||
mcpConfig: mockConfig.mcpServers,
|
||||
mcpConfig: mockConfig,
|
||||
appConnections: mockAppConnections,
|
||||
userConnections: mockUserConnections,
|
||||
oauthServers: mockOAuthServers,
|
||||
|
|
@ -165,15 +163,15 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
});
|
||||
|
||||
it('should throw error when MCP config not found', async () => {
|
||||
mockGetAppConfig.mockResolvedValue({});
|
||||
mockMcpServersRegistry.getAllServerConfigs.mockResolvedValue(null);
|
||||
await expect(getMCPSetupData(mockUserId)).rejects.toThrow('MCP config not found');
|
||||
});
|
||||
|
||||
it('should handle null values from MCP manager gracefully', async () => {
|
||||
mockGetAppConfig.mockResolvedValue({ mcpConfig: mockConfig.mcpServers });
|
||||
mockMcpServersRegistry.getAllServerConfigs.mockResolvedValue(mockConfig);
|
||||
|
||||
const mockMCPManager = {
|
||||
appConnections: { getAll: jest.fn(() => null) },
|
||||
appConnections: { getAll: jest.fn(() => Promise.resolve(null)) },
|
||||
getUserConnections: jest.fn(() => null),
|
||||
};
|
||||
mockGetMCPManager.mockReturnValue(mockMCPManager);
|
||||
|
|
@ -182,7 +180,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getMCPSetupData(mockUserId);
|
||||
|
||||
expect(result).toEqual({
|
||||
mcpConfig: mockConfig.mcpServers,
|
||||
mcpConfig: mockConfig,
|
||||
appConnections: new Map(),
|
||||
userConnections: new Map(),
|
||||
oauthServers: new Set(),
|
||||
|
|
@ -329,15 +327,25 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
describe('getServerConnectionStatus', () => {
|
||||
const mockUserId = 'user-123';
|
||||
const mockServerName = 'test-server';
|
||||
const mockConfig = { lastUpdatedAt: Date.now() };
|
||||
|
||||
it('should return app connection state when available', async () => {
|
||||
const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
|
||||
const appConnections = new Map([
|
||||
[
|
||||
mockServerName,
|
||||
{
|
||||
connectionState: 'connected',
|
||||
isStale: jest.fn(() => false),
|
||||
},
|
||||
],
|
||||
]);
|
||||
const userConnections = new Map();
|
||||
const oauthServers = new Set();
|
||||
|
||||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -351,12 +359,21 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
|
||||
it('should fallback to user connection state when app connection not available', async () => {
|
||||
const appConnections = new Map();
|
||||
const userConnections = new Map([[mockServerName, { connectionState: 'connecting' }]]);
|
||||
const userConnections = new Map([
|
||||
[
|
||||
mockServerName,
|
||||
{
|
||||
connectionState: 'connecting',
|
||||
isStale: jest.fn(() => false),
|
||||
},
|
||||
],
|
||||
]);
|
||||
const oauthServers = new Set();
|
||||
|
||||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -376,6 +393,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -388,13 +406,30 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
});
|
||||
|
||||
it('should prioritize app connection over user connection', async () => {
|
||||
const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
|
||||
const userConnections = new Map([[mockServerName, { connectionState: 'disconnected' }]]);
|
||||
const appConnections = new Map([
|
||||
[
|
||||
mockServerName,
|
||||
{
|
||||
connectionState: 'connected',
|
||||
isStale: jest.fn(() => false),
|
||||
},
|
||||
],
|
||||
]);
|
||||
const userConnections = new Map([
|
||||
[
|
||||
mockServerName,
|
||||
{
|
||||
connectionState: 'disconnected',
|
||||
isStale: jest.fn(() => false),
|
||||
},
|
||||
],
|
||||
]);
|
||||
const oauthServers = new Set();
|
||||
|
||||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -420,6 +455,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -454,6 +490,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -491,6 +528,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -524,6 +562,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -549,6 +588,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -571,13 +611,22 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
mockGetFlowStateManager.mockReturnValue(mockFlowManager);
|
||||
mockGetLogStores.mockReturnValue({});
|
||||
|
||||
const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
|
||||
const appConnections = new Map([
|
||||
[
|
||||
mockServerName,
|
||||
{
|
||||
connectionState: 'connected',
|
||||
isStale: jest.fn(() => false),
|
||||
},
|
||||
],
|
||||
]);
|
||||
const userConnections = new Map();
|
||||
const oauthServers = new Set([mockServerName]);
|
||||
|
||||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
@ -606,6 +655,7 @@ describe('tests for the new helper functions used by the MCP connection status e
|
|||
const result = await getServerConnectionStatus(
|
||||
mockUserId,
|
||||
mockServerName,
|
||||
mockConfig,
|
||||
appConnections,
|
||||
userConnections,
|
||||
oauthServers,
|
||||
|
|
|
|||
|
|
@ -427,6 +427,7 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
|
|||
|
||||
/** @type {Record<string, Record<string, string>>} */
|
||||
let userMCPAuthMap;
|
||||
//TODO pass config from registry
|
||||
if (hasCustomUserVars(req.config)) {
|
||||
userMCPAuthMap = await getUserMCPAuthMap({
|
||||
tools: agent.tools,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue