UNPKG

context-optimizer-mcp-server

Version:

Context optimization tools MCP server for AI coding assistants - compatible with GitHub Copilot, Cursor AI, and other MCP-supporting assistants

193 lines 8.38 kB
"use strict"; /** * Configuration manager for loading MCP server configuration from environment variables * * All configuration is loaded from environment variables for security and simplicity */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigurationManager = void 0; const logger_1 = require("../utils/logger"); class ConfigurationManager { static config = null; static async loadConfiguration() { logger_1.Logger.debug('Loading configuration from environment variables...'); // Build configuration from environment variables const config = { security: { allowedBasePaths: this.parseAllowedBasePaths(), maxFileSize: parseInt(process.env.CONTEXT_OPT_MAX_FILE_SIZE || '1048576', 10), commandTimeout: parseInt(process.env.CONTEXT_OPT_COMMAND_TIMEOUT || '30000', 10), sessionTimeout: parseInt(process.env.CONTEXT_OPT_SESSION_TIMEOUT || '1800000', 10) }, llm: { provider: this.getLLMProvider(), ...(process.env.CONTEXT_OPT_LLM_MODEL && { model: process.env.CONTEXT_OPT_LLM_MODEL }), ...(process.env.CONTEXT_OPT_GEMINI_KEY && { geminiKey: process.env.CONTEXT_OPT_GEMINI_KEY }), ...(process.env.CONTEXT_OPT_CLAUDE_KEY && { claudeKey: process.env.CONTEXT_OPT_CLAUDE_KEY }), ...(process.env.CONTEXT_OPT_OPENAI_KEY && { openaiKey: process.env.CONTEXT_OPT_OPENAI_KEY }) }, research: { ...(process.env.CONTEXT_OPT_EXA_KEY && { exaKey: process.env.CONTEXT_OPT_EXA_KEY }) }, server: { ...(process.env.CONTEXT_OPT_SESSION_PATH && { sessionStoragePath: process.env.CONTEXT_OPT_SESSION_PATH }), logLevel: process.env.CONTEXT_OPT_LOG_LEVEL || 'warn' } }; // Set the logger level from configuration logger_1.Logger.setLogLevel(config.server.logLevel); // Validate configuration this.validateConfiguration(config); this.config = config; logger_1.Logger.info(`Configuration loaded - provider: ${config.llm.provider}, paths: ${config.security.allowedBasePaths.length}`); return config; } static getLLMProvider() { const provider = process.env.CONTEXT_OPT_LLM_PROVIDER?.toLowerCase(); if (!provider) { throw new Error('CONTEXT_OPT_LLM_PROVIDER environment variable is required. Set to "gemini", "claude", or "openai"'); } if (!['gemini', 'claude', 'openai'].includes(provider)) { throw new Error(`Invalid CONTEXT_OPT_LLM_PROVIDER: ${provider}. Must be "gemini", "claude", or "openai"`); } return provider; } static parseAllowedBasePaths() { const pathsEnv = process.env.CONTEXT_OPT_ALLOWED_PATHS; if (!pathsEnv) { throw new Error('CONTEXT_OPT_ALLOWED_PATHS environment variable is required. Set to comma-separated list of allowed directories.'); } const paths = pathsEnv.split(',').map(p => p.trim()).filter(Boolean); if (paths.length === 0) { throw new Error('CONTEXT_OPT_ALLOWED_PATHS must contain at least one valid path'); } return paths; } static validateConfiguration(config) { // Validate security boundaries if (!config.security || !Array.isArray(config.security.allowedBasePaths)) { throw new Error('Configuration error: security.allowedBasePaths must be an array'); } if (!config.security.allowedBasePaths.length) { throw new Error('Configuration error: allowedBasePaths cannot be empty'); } // Validate security timeouts and limits if (config.security.maxFileSize <= 0) { throw new Error('Configuration error: maxFileSize must be positive'); } if (config.security.commandTimeout <= 0) { throw new Error('Configuration error: commandTimeout must be positive'); } if (config.security.sessionTimeout <= 0) { throw new Error('Configuration error: sessionTimeout must be positive'); } // Validate LLM configuration if (!config.llm || !config.llm.provider) { throw new Error('Configuration error: llm.provider is required'); } const validProviders = ['gemini', 'claude', 'openai']; if (!validProviders.includes(config.llm.provider)) { throw new Error(`Configuration error: llm.provider must be one of: ${validProviders.join(', ')}`); } const providerKey = `${config.llm.provider}Key`; if (!config.llm[providerKey]) { throw new Error(`Configuration error: ${providerKey} is required for provider ${config.llm.provider}`); } // Validate server configuration if (!config.server || !config.server.logLevel) { throw new Error('Configuration error: server.logLevel is required'); } const validLogLevels = ['error', 'warn', 'info', 'debug']; if (!validLogLevels.includes(config.server.logLevel)) { throw new Error(`Configuration error: server.logLevel must be one of: ${validLogLevels.join(', ')}`); } // Validate paths exist and are accessible (warn if they don't exist) for (const basePath of config.security.allowedBasePaths) { try { require('fs').accessSync(basePath); logger_1.Logger.debug(`Verified allowed base path: ${basePath}`); } catch { logger_1.Logger.warn(`Warning: Allowed base path does not exist: ${basePath}`); } } // Set default session storage path if not provided if (!config.server.sessionStoragePath) { const os = require('os'); const defaultPath = require('path').join(os.tmpdir(), 'context-optimizer-mcp'); config.server.sessionStoragePath = defaultPath; logger_1.Logger.debug(`Using default session storage path: ${defaultPath}`); } } static getConfig() { if (!this.config) { throw new Error('Configuration not loaded. Call loadConfiguration() first.'); } return this.config; } /** * Get configuration for a specific LLM provider */ static getLLMConfig() { const config = this.getConfig(); const provider = config.llm.provider; const keyField = `${provider}Key`; const apiKey = config.llm[keyField]; if (!apiKey) { throw new Error(`API key not configured for provider: ${provider}`); } return { provider, ...(config.llm.model ? { model: config.llm.model } : {}), apiKey }; } /** * Check if research tools are configured */ static isResearchEnabled() { try { const config = this.getConfig(); return !!config.research.exaKey; } catch { return false; } } /** * Reset configuration (useful for testing) */ static reset() { this.config = null; } /** * Get sanitized configuration for logging (removes sensitive data) */ static getSanitizedConfig() { const config = this.getConfig(); return { security: { allowedBasePaths: config.security.allowedBasePaths, maxFileSize: config.security.maxFileSize, commandTimeout: config.security.commandTimeout, sessionTimeout: config.security.sessionTimeout }, llm: { provider: config.llm.provider, model: config.llm.model, hasGeminiKey: !!config.llm.geminiKey, hasClaudeKey: !!config.llm.claudeKey, hasOpenaiKey: !!config.llm.openaiKey }, research: { hasExaKey: !!config.research.exaKey }, server: { sessionStoragePath: config.server.sessionStoragePath, logLevel: config.server.logLevel } }; } } exports.ConfigurationManager = ConfigurationManager; //# sourceMappingURL=manager.js.map