Skip to main content
Glama
config-manager.ts7.14 kB
/** * Configuration Manager - Manages tool-specific and global configurations */ import { readFile, writeFile } from 'fs/promises'; import { existsSync } from 'fs'; import { ConfigurationError } from '../errors.js'; export interface ToolConfig { enabled: boolean; timeout?: number; maxRetries?: number; cache?: { enabled: boolean; ttl: number; }; customSettings?: Record<string, any>; } export interface GlobalConfig { defaultTimeout: number; defaultMaxRetries: number; defaultCacheTTL: number; logLevel: 'error' | 'warn' | 'info' | 'debug'; tools?: Record<string, Partial<ToolConfig>>; } export class ConfigManager { private toolConfigs: Map<string, ToolConfig>; private globalConfig: GlobalConfig; private defaultToolConfig: ToolConfig = { enabled: true, timeout: 30000, // 30 seconds maxRetries: 0, cache: { enabled: false, ttl: 300, // 5 minutes }, }; constructor(globalConfig?: Partial<GlobalConfig>) { this.toolConfigs = new Map(); this.globalConfig = { defaultTimeout: 30000, defaultMaxRetries: 0, defaultCacheTTL: 300, logLevel: 'info', ...globalConfig, }; } /** * Set configuration for a specific tool */ setToolConfig(toolName: string, config: Partial<ToolConfig>): void { const existing = this.toolConfigs.get(toolName) || { ...this.defaultToolConfig }; // Merge configurations const merged: ToolConfig = { ...existing, ...config, cache: config.cache ? { ...existing.cache, ...config.cache } : existing.cache, }; this.toolConfigs.set(toolName, merged); } /** * Get configuration for a specific tool */ getToolConfig(toolName: string): ToolConfig { const config = this.toolConfigs.get(toolName); if (config) { return { ...config }; } // Return default config with global defaults return { ...this.defaultToolConfig, timeout: this.globalConfig.defaultTimeout, maxRetries: this.globalConfig.defaultMaxRetries, cache: { enabled: false, ttl: this.globalConfig.defaultCacheTTL, }, }; } /** * Get all tool configurations */ getAllToolConfigs(): Map<string, ToolConfig> { return new Map(this.toolConfigs); } /** * Enable a tool */ enableTool(toolName: string): void { const config = this.getToolConfig(toolName); config.enabled = true; this.toolConfigs.set(toolName, config); } /** * Disable a tool */ disableTool(toolName: string): void { const config = this.getToolConfig(toolName); config.enabled = false; this.toolConfigs.set(toolName, config); } /** * Check if a tool is enabled */ isToolEnabled(toolName: string): boolean { const config = this.getToolConfig(toolName); return config.enabled; } /** * Set global configuration */ setGlobalConfig(config: Partial<GlobalConfig>): void { this.globalConfig = { ...this.globalConfig, ...config, }; // Update default tool config with new global defaults this.defaultToolConfig = { ...this.defaultToolConfig, timeout: this.globalConfig.defaultTimeout, maxRetries: this.globalConfig.defaultMaxRetries, }; } /** * Get global configuration */ getGlobalConfig(): GlobalConfig { return { ...this.globalConfig }; } /** * Load configuration from a file */ async loadFromFile(filePath: string): Promise<void> { if (!existsSync(filePath)) { throw new ConfigurationError( `Configuration file not found: ${filePath}`, filePath ); } try { const content = await readFile(filePath, 'utf-8'); const config = JSON.parse(content); // Load global config if (config.global) { this.setGlobalConfig(config.global); } // Load tool-specific configs if (config.tools) { for (const [toolName, toolConfig] of Object.entries(config.tools)) { this.setToolConfig(toolName, toolConfig as Partial<ToolConfig>); } } console.error(`Loaded configuration from ${filePath}`); } catch (error) { throw new ConfigurationError( `Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`, filePath ); } } /** * Save configuration to a file */ async saveToFile(filePath: string): Promise<void> { try { const config = { global: this.globalConfig, tools: Object.fromEntries(this.toolConfigs), }; await writeFile(filePath, JSON.stringify(config, null, 2)); console.error(`Saved configuration to ${filePath}`); } catch (error) { throw new ConfigurationError( `Failed to save configuration: ${error instanceof Error ? error.message : 'Unknown error'}`, filePath ); } } /** * Reset all configurations to default */ reset(): void { this.toolConfigs.clear(); this.globalConfig = { defaultTimeout: 30000, defaultMaxRetries: 0, defaultCacheTTL: 300, logLevel: 'info', }; } /** * Get configuration summary */ getSummary(): { totalTools: number; enabledTools: number; disabledTools: number; globalConfig: GlobalConfig; } { const allConfigs = Array.from(this.toolConfigs.values()); return { totalTools: allConfigs.length, enabledTools: allConfigs.filter(c => c.enabled).length, disabledTools: allConfigs.filter(c => !c.enabled).length, globalConfig: this.getGlobalConfig(), }; } /** * Validate tool configuration */ validateToolConfig(config: Partial<ToolConfig>): { valid: boolean; errors: string[] } { const errors: string[] = []; if (config.timeout !== undefined) { if (typeof config.timeout !== 'number' || config.timeout <= 0) { errors.push('Timeout must be a positive number'); } } if (config.maxRetries !== undefined) { if (typeof config.maxRetries !== 'number' || config.maxRetries < 0) { errors.push('Max retries must be a non-negative number'); } } if (config.cache) { if (config.cache.ttl !== undefined) { if (typeof config.cache.ttl !== 'number' || config.cache.ttl <= 0) { errors.push('Cache TTL must be a positive number'); } } } return { valid: errors.length === 0, errors, }; } } // Global singleton instance let globalConfigManager: ConfigManager | null = null; /** * Get the global configuration manager instance */ export function getConfigManager(): ConfigManager { if (!globalConfigManager) { globalConfigManager = new ConfigManager(); } return globalConfigManager; } /** * Initialize the global configuration manager with a config file */ export async function initializeConfigManager(configPath?: string): Promise<ConfigManager> { const manager = getConfigManager(); if (configPath && existsSync(configPath)) { await manager.loadFromFile(configPath); } return manager; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/krtw00/search-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server