Skip to main content
Glama
configuration.ts12.1 kB
import { z } from 'zod'; import dotenv from 'dotenv'; // Load environment variables from .env file in development dotenv.config(); /** * Workflow configuration schema with enhanced validation */ const WorkflowConfigSchema = z.object({ workflowsEnabled: z.boolean().default(false), workflowDiscoveryInterval: z.number() .min(0, 'Workflow discovery interval must be 0 or positive (0 = disabled)') .max(86400000, 'Workflow discovery interval cannot exceed 24 hours (86400000ms)') .default(0), workflowExecutionTimeout: z.number() .positive('Workflow execution timeout must be positive') .min(1000, 'Workflow execution timeout must be at least 1000ms (1 second)') .max(3600000, 'Workflow execution timeout cannot exceed 1 hour (3600000ms)') .default(300000), // 5 minutes workflowMaxConcurrentExecutions: z.number() .positive('Maximum concurrent executions must be positive') .min(1, 'Maximum concurrent executions must be at least 1') .max(100, 'Maximum concurrent executions cannot exceed 100') .default(10), workflowFilterPatterns: z.array(z.string().min(1, 'Filter patterns cannot be empty strings')) .default([]) .refine(patterns => patterns.every(pattern => pattern.trim() === pattern), { message: 'Filter patterns cannot have leading or trailing whitespace' }), workflowStatusCheckInterval: z.number() .positive('Status check interval must be positive') .min(1000, 'Status check interval must be at least 1000ms to avoid excessive API calls') .max(300000, 'Status check interval cannot exceed 5 minutes (300000ms)') .default(5000), // 5 seconds workflowRetryAttempts: z.number() .min(0, 'Retry attempts must be 0 or positive') .max(10, 'Retry attempts cannot exceed 10') .default(3) }); /** * Configuration schema for validation */ const ConfigSchema = z.object({ apiToken: z.string().min(1, 'API_TOKEN'), apiBaseUrl: z.string().url().default('https://api.simplified.com'), logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'), timeout: z.number().positive().default(30000), retryAttempts: z.number().min(0).default(3), retryDelay: z.number().positive().default(1000) }).merge(WorkflowConfigSchema); /** * Configuration type derived from schema */ export type ServerConfig = z.infer<typeof ConfigSchema>; /** * Configuration Manager handles loading and validating server configuration */ export class ConfigurationManager { /** * Load configuration from environment variables * @returns Validated server configuration * @throws Error if required configuration is missing or invalid */ static loadConfig(): ServerConfig { const rawConfig = { apiToken: process.env.SIMPLIFIED_API_TOKEN, apiBaseUrl: process.env.SIMPLIFIED_API_BASE_URL, logLevel: process.env.LOG_LEVEL, timeout: process.env.REQUEST_TIMEOUT ? parseInt(process.env.REQUEST_TIMEOUT, 10) : undefined, retryAttempts: process.env.RETRY_ATTEMPTS ? parseInt(process.env.RETRY_ATTEMPTS, 10) : undefined, retryDelay: process.env.RETRY_DELAY ? parseInt(process.env.RETRY_DELAY, 10) : undefined, // Workflow configuration workflowsEnabled: process.env.WORKFLOWS_ENABLED ? process.env.WORKFLOWS_ENABLED.toLowerCase() === 'true' : undefined, workflowDiscoveryInterval: process.env.WORKFLOW_DISCOVERY_INTERVAL ? parseInt(process.env.WORKFLOW_DISCOVERY_INTERVAL, 10) : undefined, workflowExecutionTimeout: process.env.WORKFLOW_EXECUTION_TIMEOUT ? parseInt(process.env.WORKFLOW_EXECUTION_TIMEOUT, 10) : undefined, workflowMaxConcurrentExecutions: process.env.WORKFLOW_MAX_CONCURRENT_EXECUTIONS ? parseInt(process.env.WORKFLOW_MAX_CONCURRENT_EXECUTIONS, 10) : undefined, workflowFilterPatterns: process.env.WORKFLOW_FILTER_PATTERNS ? process.env.WORKFLOW_FILTER_PATTERNS.split(',').map(p => p.trim()).filter(p => p.length > 0) : undefined, workflowStatusCheckInterval: process.env.WORKFLOW_STATUS_CHECK_INTERVAL ? parseInt(process.env.WORKFLOW_STATUS_CHECK_INTERVAL, 10) : undefined, workflowRetryAttempts: process.env.WORKFLOW_RETRY_ATTEMPTS ? parseInt(process.env.WORKFLOW_RETRY_ATTEMPTS, 10) : undefined }; try { return this.validateConfig(rawConfig); } catch (error) { if (error instanceof z.ZodError) { const missingFields = error.errors .filter(err => err.code === 'invalid_type' && err.received === 'undefined') .map(err => err.path.join('.')); const invalidFields = error.errors .filter(err => err.code !== 'invalid_type' || err.received !== 'undefined') .map(err => `${err.path.join('.')}: ${err.message}`); let errorMessage = 'Configuration validation failed:\n'; if (missingFields.length > 0) { errorMessage += `Missing required environment variables: ${missingFields.join(', ')}\n`; } if (invalidFields.length > 0) { errorMessage += `Invalid configuration values: ${invalidFields.join(', ')}\n`; } errorMessage += '\nRequired environment variables:\n'; errorMessage += '- SIMPLIFIED_API_TOKEN: Your Simplified API token\n'; errorMessage += '\nOptional environment variables:\n'; errorMessage += '- SIMPLIFIED_API_BASE_URL: API base URL (default: https://api.simplified.com)\n'; errorMessage += '- LOG_LEVEL: Logging level (debug|info|warn|error, default: info)\n'; errorMessage += '- REQUEST_TIMEOUT: Request timeout in milliseconds (default: 30000)\n'; errorMessage += '- RETRY_ATTEMPTS: Number of retry attempts (default: 3)\n'; errorMessage += '- RETRY_DELAY: Delay between retries in milliseconds (default: 1000)\n'; errorMessage += '\nWorkflow configuration (optional):\n'; errorMessage += '- WORKFLOWS_ENABLED: Enable dynamic workflow tools (true|false, default: false)\n'; errorMessage += '- WORKFLOW_DISCOVERY_INTERVAL: Auto-refresh interval in ms (0-86400000, default: 0=disabled)\n'; errorMessage += '- WORKFLOW_EXECUTION_TIMEOUT: Execution timeout in ms (1000-3600000, default: 300000)\n'; errorMessage += '- WORKFLOW_MAX_CONCURRENT_EXECUTIONS: Max concurrent executions (1-100, default: 10)\n'; errorMessage += '- WORKFLOW_FILTER_PATTERNS: Comma-separated workflow name patterns (default: none)\n'; errorMessage += '- WORKFLOW_STATUS_CHECK_INTERVAL: Status polling interval in ms (1000-300000, default: 5000)\n'; errorMessage += '- WORKFLOW_RETRY_ATTEMPTS: Retry attempts for failed operations (0-10, default: 3)\n'; // Add specific workflow configuration guidance errorMessage += '\nWorkflow configuration guidelines:\n'; errorMessage += '- Set WORKFLOW_DISCOVERY_INTERVAL to 0 to disable automatic refresh\n'; errorMessage += '- Use WORKFLOW_FILTER_PATTERNS to limit which workflows are exposed (e.g., "data-*,report-*")\n'; errorMessage += '- Minimum WORKFLOW_STATUS_CHECK_INTERVAL is 1000ms to avoid excessive API calls\n'; errorMessage += '- WORKFLOW_EXECUTION_TIMEOUT should be set based on your longest-running workflows\n'; throw new Error(errorMessage); } throw error; } } /** * Validate configuration object against schema * @param config Raw configuration object * @returns Validated configuration * @throws ZodError if validation fails */ static validateConfig(config: unknown): ServerConfig { return ConfigSchema.parse(config); } /** * Get list of required environment variables * @returns Array of required environment variable names */ static getRequiredEnvironmentVariables(): string[] { return ['SIMPLIFIED_API_TOKEN']; } /** * Get list of optional environment variables with their defaults * @returns Object mapping optional environment variables to their default values */ static getOptionalEnvironmentVariables(): Record<string, string | number | boolean> { return { SIMPLIFIED_API_BASE_URL: 'https://api.simplified.com', LOG_LEVEL: 'info', REQUEST_TIMEOUT: 30000, RETRY_ATTEMPTS: 3, RETRY_DELAY: 1000, WORKFLOWS_ENABLED: false, WORKFLOW_DISCOVERY_INTERVAL: 0, WORKFLOW_EXECUTION_TIMEOUT: 300000, WORKFLOW_MAX_CONCURRENT_EXECUTIONS: 10, WORKFLOW_FILTER_PATTERNS: '', WORKFLOW_STATUS_CHECK_INTERVAL: 5000, WORKFLOW_RETRY_ATTEMPTS: 3 }; } /** * Validate workflow-specific configuration and provide recommendations * @param config Configuration object to validate * @returns Array of validation warnings and recommendations */ static validateWorkflowConfiguration(config: ServerConfig): string[] { const warnings: string[] = []; // Check for potentially problematic configurations if (config.workflowsEnabled) { if (config.workflowDiscoveryInterval > 0 && config.workflowDiscoveryInterval < 60000) { warnings.push('WORKFLOW_DISCOVERY_INTERVAL is less than 60 seconds. Consider using a longer interval to reduce API load.'); } if (config.workflowExecutionTimeout < 30000) { warnings.push('WORKFLOW_EXECUTION_TIMEOUT is less than 30 seconds. This may cause timeouts for longer-running workflows.'); } if (config.workflowMaxConcurrentExecutions > 50) { warnings.push('WORKFLOW_MAX_CONCURRENT_EXECUTIONS is very high. This may cause resource exhaustion.'); } if (config.workflowStatusCheckInterval < 2000) { warnings.push('WORKFLOW_STATUS_CHECK_INTERVAL is less than 2 seconds. This may cause excessive API calls.'); } if (config.workflowRetryAttempts > 5) { warnings.push('WORKFLOW_RETRY_ATTEMPTS is high. This may cause long delays on failures.'); } // Check filter patterns for common issues if (config.workflowFilterPatterns.length > 0) { const hasWildcard = config.workflowFilterPatterns.some(pattern => pattern.includes('*') || pattern.includes('?')); if (!hasWildcard) { warnings.push('WORKFLOW_FILTER_PATTERNS contains no wildcards. Consider using patterns like "prefix-*" for flexibility.'); } } } return warnings; } /** * Get workflow configuration recommendations based on environment * @param environment Environment type ('development' | 'production' | 'testing') * @returns Object with recommended configuration values */ static getWorkflowConfigurationRecommendations(environment: 'development' | 'production' | 'testing'): Partial<ServerConfig> { switch (environment) { case 'development': return { workflowsEnabled: true, workflowDiscoveryInterval: 60000, // 1 minute for faster development feedback workflowExecutionTimeout: 120000, // 2 minutes for faster feedback workflowMaxConcurrentExecutions: 5, // Lower for development workflowStatusCheckInterval: 2000, // 2 seconds for faster feedback workflowRetryAttempts: 1 // Fewer retries for faster failure feedback }; case 'production': return { workflowsEnabled: true, workflowDiscoveryInterval: 600000, // 10 minutes for stability workflowExecutionTimeout: 600000, // 10 minutes for longer workloads workflowMaxConcurrentExecutions: 20, // Higher for production load workflowStatusCheckInterval: 10000, // 10 seconds to reduce API load workflowRetryAttempts: 5 // More retries for reliability }; case 'testing': return { workflowsEnabled: false, // Disabled by default for testing workflowDiscoveryInterval: 0, // Disabled workflowExecutionTimeout: 30000, // 30 seconds for fast tests workflowMaxConcurrentExecutions: 3, // Low for testing workflowStatusCheckInterval: 1000, // 1 second minimum workflowRetryAttempts: 0 // No retries for predictable testing }; default: return {}; } } }

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/celeryhq/simplified-mcp-server'

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