import { ServerConfig } from '../types/index.js'; import { BaseDao } from './base/BaseDao.js'; import { JsonFileBaseDao } from './base/JsonFileBaseDao.js'; /** * Server DAO interface with server-specific operations */ export interface ServerDao extends BaseDao { /** * Find servers by owner */ findByOwner(owner: string): Promise; /** * Find enabled servers only */ findEnabled(): Promise; /** * Find servers by type */ findByType(type: string): Promise; /** * Enable/disable server */ setEnabled(name: string, enabled: boolean): Promise; /** * Update server tools configuration */ updateTools( name: string, tools: Record, ): Promise; /** * Update server prompts configuration */ updatePrompts( name: string, prompts: Record, ): Promise; /** * Rename a server (change its name/key) */ rename(oldName: string, newName: string): Promise; } /** * Server configuration with name for DAO operations */ export interface ServerConfigWithName extends ServerConfig { name: string; } /** * JSON file-based Server DAO implementation */ export class ServerDaoImpl extends JsonFileBaseDao implements ServerDao { protected async getAll(): Promise { const settings = await this.loadSettings(); const servers: ServerConfigWithName[] = []; for (const [name, config] of Object.entries(settings.mcpServers || {})) { servers.push({ name, ...config, }); } return servers; } protected async saveAll(servers: ServerConfigWithName[]): Promise { const settings = await this.loadSettings(); settings.mcpServers = {}; for (const server of servers) { const { name, ...config } = server; settings.mcpServers[name] = config; } await this.saveSettings(settings); } protected getEntityId(server: ServerConfigWithName): string { return server.name; } protected createEntity(_data: Omit): ServerConfigWithName { throw new Error('Server name must be provided'); } protected updateEntity( existing: ServerConfigWithName, updates: Partial, ): ServerConfigWithName { return { ...existing, ...updates, // Keep the existing name unless explicitly updating via rename name: updates.name ?? existing.name, }; } async findAll(): Promise { return this.getAll(); } async findById(name: string): Promise { const servers = await this.getAll(); return servers.find((server) => server.name === name) || null; } async create( data: Omit & { name: string }, ): Promise { const servers = await this.getAll(); // Check if server already exists if (servers.find((server) => server.name === data.name)) { throw new Error(`Server ${data.name} already exists`); } const newServer: ServerConfigWithName = { enabled: true, // Default to enabled owner: 'admin', // Default owner ...data, }; servers.push(newServer); await this.saveAll(servers); return newServer; } async update( name: string, updates: Partial, ): Promise { const servers = await this.getAll(); const index = servers.findIndex((server) => server.name === name); if (index === -1) { return null; } const updatedServer = this.updateEntity(servers[index], updates); servers[index] = updatedServer; await this.saveAll(servers); return updatedServer; } async delete(name: string): Promise { const servers = await this.getAll(); const index = servers.findIndex((server) => server.name === name); if (index === -1) { return false; } servers.splice(index, 1); await this.saveAll(servers); return true; } async exists(name: string): Promise { const server = await this.findById(name); return server !== null; } async count(): Promise { const servers = await this.getAll(); return servers.length; } async findByOwner(owner: string): Promise { const servers = await this.getAll(); return servers.filter((server) => server.owner === owner); } async findEnabled(): Promise { const servers = await this.getAll(); return servers.filter((server) => server.enabled !== false); } async findByType(type: string): Promise { const servers = await this.getAll(); return servers.filter((server) => server.type === type); } async setEnabled(name: string, enabled: boolean): Promise { const result = await this.update(name, { enabled }); return result !== null; } async updateTools( name: string, tools: Record, ): Promise { const result = await this.update(name, { tools }); return result !== null; } async updatePrompts( name: string, prompts: Record, ): Promise { const result = await this.update(name, { prompts }); return result !== null; } async rename(oldName: string, newName: string): Promise { const servers = await this.getAll(); const index = servers.findIndex((server) => server.name === oldName); if (index === -1) { return false; } // Check if newName already exists if (servers.find((server) => server.name === newName)) { throw new Error(`Server ${newName} already exists`); } servers[index] = { ...servers[index], name: newName }; await this.saveAll(servers); return true; } }