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
JavaScript
/**
* 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
;