| | import type Keyv from 'keyv'; |
| | import { fromPairs } from 'lodash'; |
| | import { standardCache, keyvRedisClient } from '~/cache'; |
| | import { ParsedServerConfig } from '~/mcp/types'; |
| | import { BaseRegistryCache } from './BaseRegistryCache'; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export class ServerConfigsCacheRedis extends BaseRegistryCache { |
| | protected readonly cache: Keyv; |
| | private readonly owner: string; |
| | private readonly leaderOnly: boolean; |
| |
|
| | constructor(owner: string, leaderOnly: boolean) { |
| | super(); |
| | this.owner = owner; |
| | this.leaderOnly = leaderOnly; |
| | this.cache = standardCache(`${this.PREFIX}::Servers::${owner}`); |
| | } |
| |
|
| | public async add(serverName: string, config: ParsedServerConfig): Promise<void> { |
| | if (this.leaderOnly) await this.leaderCheck(`add ${this.owner} MCP servers`); |
| | const exists = await this.cache.has(serverName); |
| | if (exists) |
| | throw new Error( |
| | `Server "${serverName}" already exists in cache. Use update() to modify existing configs.`, |
| | ); |
| | const success = await this.cache.set(serverName, config); |
| | this.successCheck(`add ${this.owner} server "${serverName}"`, success); |
| | } |
| |
|
| | public async update(serverName: string, config: ParsedServerConfig): Promise<void> { |
| | if (this.leaderOnly) await this.leaderCheck(`update ${this.owner} MCP servers`); |
| | const exists = await this.cache.has(serverName); |
| | if (!exists) |
| | throw new Error( |
| | `Server "${serverName}" does not exist in cache. Use add() to create new configs.`, |
| | ); |
| | const success = await this.cache.set(serverName, config); |
| | this.successCheck(`update ${this.owner} server "${serverName}"`, success); |
| | } |
| |
|
| | public async remove(serverName: string): Promise<void> { |
| | if (this.leaderOnly) await this.leaderCheck(`remove ${this.owner} MCP servers`); |
| | const success = await this.cache.delete(serverName); |
| | this.successCheck(`remove ${this.owner} server "${serverName}"`, success); |
| | } |
| |
|
| | public async get(serverName: string): Promise<ParsedServerConfig | undefined> { |
| | return this.cache.get(serverName); |
| | } |
| |
|
| | public async getAll(): Promise<Record<string, ParsedServerConfig>> { |
| | |
| | |
| | const pattern = `*${this.cache.namespace}:*`; |
| | const entries: Array<[string, ParsedServerConfig]> = []; |
| |
|
| | |
| | if (keyvRedisClient && 'scanIterator' in keyvRedisClient) { |
| | for await (const key of keyvRedisClient.scanIterator({ MATCH: pattern })) { |
| | |
| | |
| | const lastColonIndex = key.lastIndexOf(':'); |
| | const keyName = key.substring(lastColonIndex + 1); |
| | const value = await this.cache.get(keyName); |
| | if (value) { |
| | entries.push([keyName, value as ParsedServerConfig]); |
| | } |
| | } |
| | } else { |
| | throw new Error('Redis client with scanIterator not available.'); |
| | } |
| |
|
| | return fromPairs(entries); |
| | } |
| | } |
| |
|