/**
* Environment variable configuration for Komodo MCP Server
*/
import { ConfigurationError } from './utils/errors.js';
import type { KomodoConfig } from './types/index.js';
/**
* Load configuration from environment variables
*/
export function loadConfig(): KomodoConfig {
// Required environment variables
const url = process.env.KOMODO_URL;
const apiKey = process.env.KOMODO_API_KEY;
const apiSecret = process.env.KOMODO_API_SECRET;
// Validate required variables
if (!url) {
throw new ConfigurationError(
'KOMODO_URL environment variable is required',
{ variable: 'KOMODO_URL' }
);
}
if (!apiKey) {
throw new ConfigurationError(
'KOMODO_API_KEY environment variable is required',
{ variable: 'KOMODO_API_KEY' }
);
}
if (!apiSecret) {
throw new ConfigurationError(
'KOMODO_API_SECRET environment variable is required',
{ variable: 'KOMODO_API_SECRET' }
);
}
// Optional environment variables with defaults
const timeout = parseNumber(process.env.KOMODO_TIMEOUT, 30000);
const retryCount = parseNumber(process.env.KOMODO_RETRY_COUNT, 3);
const retryDelay = parseNumber(process.env.KOMODO_RETRY_DELAY, 1000);
const logLevel = parseLogLevel(process.env.KOMODO_LOG_LEVEL);
// SSL verification - defaults to true
// SECURITY WARNING: Disabling SSL verification is dangerous and should only be done in development
const sslVerify = parseBoolean(process.env.KOMODO_SSL_VERIFY, true);
const caCertPath = process.env.KOMODO_CA_CERT_PATH;
// SECURITY: Prevent SSL bypass in production
if (process.env.NODE_ENV === 'production' && sslVerify === false) {
throw new ConfigurationError(
'SSL verification cannot be disabled in production environment',
{
environment: process.env.NODE_ENV,
sslVerify
}
);
}
// Warn if SSL verification is disabled
if (sslVerify === false) {
console.warn('⚠️ WARNING: SSL verification is DISABLED. This is insecure and should only be used in development!');
console.warn('⚠️ Your connection is vulnerable to man-in-the-middle attacks.');
console.warn('⚠️ Set KOMODO_SSL_VERIFY=true or remove the setting to enable SSL verification.');
}
// Validate URL format
try {
new URL(url);
} catch (error) {
throw new ConfigurationError(
`Invalid KOMODO_URL: ${url}`,
{ url, error }
);
}
// Validate timeout
if (timeout < 1000) {
throw new ConfigurationError(
'KOMODO_TIMEOUT must be at least 1000ms',
{ timeout }
);
}
// Validate retry count
if (retryCount < 0 || retryCount > 10) {
throw new ConfigurationError(
'KOMODO_RETRY_COUNT must be between 0 and 10',
{ retryCount }
);
}
// Validate retry delay
if (retryDelay < 0) {
throw new ConfigurationError(
'KOMODO_RETRY_DELAY must be non-negative',
{ retryDelay }
);
}
return {
url: url.replace(/\/$/, ''), // Remove trailing slash
apiKey,
apiSecret,
timeout,
retryCount,
retryDelay,
logLevel,
sslVerify,
caCertPath
};
}
/**
* Parse a string to number with default fallback
*/
function parseNumber(value: string | undefined, defaultValue: number): number {
if (!value) {
return defaultValue;
}
const parsed = parseInt(value, 10);
if (isNaN(parsed)) {
return defaultValue;
}
return parsed;
}
/**
* Parse a string to boolean with default fallback
*/
function parseBoolean(value: string | undefined, defaultValue: boolean): boolean {
if (!value) {
return defaultValue;
}
const normalized = value.toLowerCase().trim();
if (normalized === 'true' || normalized === '1' || normalized === 'yes') {
return true;
}
if (normalized === 'false' || normalized === '0' || normalized === 'no') {
return false;
}
return defaultValue;
}
/**
* Parse log level with validation
*/
function parseLogLevel(value: string | undefined): 'debug' | 'info' | 'warn' | 'error' {
if (!value) {
return 'info';
}
const normalized = value.toLowerCase();
if (['debug', 'info', 'warn', 'error'].includes(normalized)) {
return normalized as 'debug' | 'info' | 'warn' | 'error';
}
return 'info';
}
/**
* Validate configuration object
*/
export function validateConfig(config: KomodoConfig): void {
if (!config.url || !config.apiKey || !config.apiSecret) {
throw new ConfigurationError(
'Configuration is missing required fields',
{ config: { ...config, apiSecret: '[REDACTED]' } }
);
}
}
/**
* Get sanitized config for logging (redacts secrets)
*/
export function getSanitizedConfig(config: KomodoConfig): Partial<KomodoConfig> {
return {
url: config.url,
apiKey: config.apiKey.substring(0, 10) + '...',
timeout: config.timeout,
retryCount: config.retryCount,
retryDelay: config.retryDelay,
logLevel: config.logLevel,
sslVerify: config.sslVerify,
caCertPath: config.caCertPath
};
}