🪂 refactor: MCP Server Init Fallback (#10608)

* 🌿 refactor: MCP Server Init and Registry with Fallback Configs

* chore: Redis Cache Flushing for Cluster Support
This commit is contained in:
Danny Avila 2025-11-20 16:47:00 -05:00 committed by GitHub
parent 1e4c255351
commit b49545d916
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 99 additions and 38 deletions

View file

@ -34,6 +34,9 @@ export class MCPServersInitializer {
public static async initialize(rawConfigs: t.MCPServers): Promise<void> {
if (await statusCache.isInitialized()) return;
/** Store raw configs immediately so they're available even if initialization fails/is slow */
registry.setRawConfigs(rawConfigs);
if (await isLeader()) {
// Leader performs initialization
await statusCache.reset();

View file

@ -13,12 +13,22 @@ import {
*
* Provides a unified interface for retrieving server configs with proper fallback hierarchy:
* checks shared app servers first, then shared user servers, then private user servers.
* Falls back to raw config when servers haven't been initialized yet or failed to initialize.
* Handles server lifecycle operations including adding, removing, and querying configurations.
*/
class MCPServersRegistry {
public readonly sharedAppServers = ServerConfigsCacheFactory.create('App', false);
public readonly sharedUserServers = ServerConfigsCacheFactory.create('User', false);
private readonly privateUserServers: Map<string | undefined, ServerConfigsCache> = new Map();
private rawConfigs: t.MCPServers = {};
/**
* Stores the raw MCP configuration as a fallback when servers haven't been initialized yet.
* Should be called during initialization before inspecting servers.
*/
public setRawConfigs(configs: t.MCPServers): void {
this.rawConfigs = configs;
}
public async addPrivateUserServer(
userId: string,
@ -59,15 +69,32 @@ class MCPServersRegistry {
const privateUserServer = await this.privateUserServers.get(userId)?.get(serverName);
if (privateUserServer) return privateUserServer;
/** Fallback to raw config if server hasn't been initialized yet */
const rawConfig = this.rawConfigs[serverName];
if (rawConfig) return rawConfig as t.ParsedServerConfig;
return undefined;
}
public async getAllServerConfigs(userId?: string): Promise<Record<string, t.ParsedServerConfig>> {
return {
const registryConfigs = {
...(await this.sharedAppServers.getAll()),
...(await this.sharedUserServers.getAll()),
...((await this.privateUserServers.get(userId)?.getAll()) ?? {}),
};
/** Include all raw configs, but registry configs take precedence (they have inspection data) */
const allConfigs: Record<string, t.ParsedServerConfig> = {};
for (const serverName in this.rawConfigs) {
allConfigs[serverName] = this.rawConfigs[serverName] as t.ParsedServerConfig;
}
/** Override with registry configs where available (they have richer data) */
for (const serverName in registryConfigs) {
allConfigs[serverName] = registryConfigs[serverName];
}
return allConfigs;
}
// TODO: This is currently used to determine if a server requires OAuth. However, this info can