🧩 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:
Atef Bellaaj 2025-11-26 21:26:40 +01:00 committed by Danny Avila
parent 98b188f26c
commit ef1b7f0157
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
36 changed files with 548 additions and 301 deletions

View file

@ -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,
};