mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
* 🔄 Refactoring: MCP Runtime Configuration Reload
- PrivateServerConfigs own cache classes (inMemory and Redis).
- Connections staleness detection by comparing (connection.createdAt and config.LastUpdatedAt)
- ConnectionsRepo access Registry instead of in memory config dict and renew stale connections
- MCPManager: adjusted init of ConnectionsRepo (app level)
- UserConnectionManager: renew stale connections
- skipped test, to test "should only clear keys in its own namespace"
- MCPPrivateServerLoader: new component to manage logic of loading / editing private servers on runtime
- PrivateServersLoadStatusCache to track private server cache status
- New unit and integration tests.
Misc:
- add es lint rule to enforce line between class methods
* Fix cluster mode batch update and delete workarround. Fixed unit tests for cluster mode.
* Fix Keyv redis clear cache namespace awareness issue + Integration tests fixes
* chore: address copilot comments
* Fixing rebase issue: removed the mcp config fallback in single getServerConfig method:
- to not to interfere with the logic of the right Tier (APP/USER/Private)
- If userId is null, the getServerConfig should not return configs that are a SharedUser tier and not APP tier
* chore: add dev-staging branch to workflow triggers for backend, cache integration, and ESLint checks
---------
Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com>
33 lines
1 KiB
TypeScript
33 lines
1 KiB
TypeScript
import type Keyv from 'keyv';
|
|
import { isLeader } from '~/cluster';
|
|
|
|
/**
|
|
* Base class for MCP registry caches that require distributed leader coordination.
|
|
* Provides helper methods for leader-only operations and success validation.
|
|
* All concrete implementations must provide their own Keyv cache instance.
|
|
*/
|
|
export abstract class BaseRegistryCache {
|
|
protected readonly PREFIX = 'MCP::ServersRegistry';
|
|
protected abstract readonly cache: Keyv;
|
|
protected readonly leaderOnly: boolean;
|
|
|
|
constructor(leaderOnly?: boolean) {
|
|
this.leaderOnly = leaderOnly ?? false;
|
|
}
|
|
|
|
protected async leaderCheck(action: string): Promise<void> {
|
|
if (!(await isLeader())) throw new Error(`Only leader can ${action}.`);
|
|
}
|
|
|
|
protected successCheck(action: string, success: boolean): true {
|
|
if (!success) throw new Error(`Failed to ${action} in cache.`);
|
|
return true;
|
|
}
|
|
|
|
public async reset(): Promise<void> {
|
|
if (this.leaderOnly) {
|
|
await this.leaderCheck(`reset ${this.cache.namespace} cache`);
|
|
}
|
|
await this.cache.clear();
|
|
}
|
|
}
|