UNPKG

@aurracloud/mcp-cli

Version:

A command-line tool to install, manage, and setup MCP (Model Context Protocol) servers with Docker support

328 lines 11.1 kB
"use strict"; /** * MCP Server Configuration Validator * * Validates MCP server configurations against the schema v1 specification. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.validateMcpServerConfig = validateMcpServerConfig; exports.validatePackageJsonWithMcp = validatePackageJsonWithMcp; exports.createDefaultParseOptions = createDefaultParseOptions; /** * Validates a value against a format constraint */ function validateFormat(value, format) { if (typeof value !== 'string') return false; const patterns = { uri: /^https?:\/\/[^\s/$.?#].[^\s]*$/i, email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, path: /^[^\0]+$/, // Basic path validation (no null bytes) date: /^\d{4}-\d{2}-\d{2}$/, time: /^\d{2}:\d{2}:\d{2}$/, 'date-time': /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/, uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, hostname: /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/, ipv4: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, ipv6: /^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i }; const pattern = patterns[format]; return pattern ? pattern.test(value) : true; } /** * Validates a configuration item value */ function validateConfigItem(value, config, path, options = {}) { const errors = []; // Type validation const expectedType = config.type; const actualType = Array.isArray(value) ? 'array' : typeof value; if (actualType !== expectedType) { errors.push({ path, message: `Expected type '${expectedType}' but got '${actualType}'`, value }); return errors; // Don't continue validation if type is wrong } // Numeric range validation if (expectedType === 'number') { if (config.minimum !== undefined && value < config.minimum) { errors.push({ path, message: `Value ${value} is below minimum ${config.minimum}`, value }); } if (config.maximum !== undefined && value > config.maximum) { errors.push({ path, message: `Value ${value} is above maximum ${config.maximum}`, value }); } } // String pattern validation if (expectedType === 'string' && config.pattern) { const regex = new RegExp(config.pattern); if (!regex.test(value)) { errors.push({ path, message: `Value '${value}' does not match pattern '${config.pattern}'`, value }); } } // Enum validation if (config.enum && !config.enum.includes(value)) { errors.push({ path, message: `Value '${value}' is not one of allowed values: ${config.enum.join(', ')}`, value }); } // Format validation if (expectedType === 'string' && config.format && options.validateFormats) { if (!validateFormat(value, config.format)) { errors.push({ path, message: `Value '${value}' does not match format '${config.format}'`, value }); } } // Array items validation if (expectedType === 'array' && config.items && Array.isArray(value)) { value.forEach((item, index) => { const itemErrors = validateConfigItem(item, config.items, `${path}[${index}]`, options); errors.push(...itemErrors); }); } return errors; } /** * Validates connection configuration */ function validateConnection(connection, path) { const errors = []; // Required fields based on connection type if (connection.type === 'stdio') { if (!connection.command) { errors.push({ path: `${path}.command`, message: 'Command is required for stdio connection type' }); } } else if (connection.type === 'http' || connection.type === 'sse') { if (!connection.url) { errors.push({ path: `${path}.url`, message: `URL is required for ${connection.type} connection type` }); } else if (!validateFormat(connection.url, 'uri')) { errors.push({ path: `${path}.url`, message: 'URL must be a valid URI', value: connection.url }); } } // Timeout validation if (connection.timeout !== undefined) { if (connection.timeout < 1000 || connection.timeout > 300000) { errors.push({ path: `${path}.timeout`, message: 'Timeout must be between 1000 and 300000 milliseconds', value: connection.timeout }); } } return errors; } /** * Validates file configuration */ function validateFileConfig(fileConfig, path) { const errors = []; if (!fileConfig.path) { errors.push({ path: `${path}.path`, message: 'File path is required' }); } if (!fileConfig.description) { errors.push({ path: `${path}.description`, message: 'File description is required' }); } const validFormats = ['json', 'yaml', 'toml', 'ini', 'env', 'text']; if (fileConfig.format && !validFormats.includes(fileConfig.format)) { errors.push({ path: `${path}.format`, message: `Invalid file format '${fileConfig.format}'. Must be one of: ${validFormats.join(', ')}`, value: fileConfig.format }); } return errors; } /** * Validates a configuration section (environment or arguments) */ function validateConfigSection(section, path, options = {}) { const errors = []; if (!section) return errors; // Validate required items if (section.required) { Object.entries(section.required).forEach(([key, config]) => { const itemErrors = validateConfigItem(config.default, // We're validating the config structure, not actual values config, `${path}.required.${key}`, options); errors.push(...itemErrors); }); } // Validate optional items if (section.optional) { Object.entries(section.optional).forEach(([key, config]) => { const itemErrors = validateConfigItem(config.default, // We're validating the config structure, not actual values config, `${path}.optional.${key}`, options); errors.push(...itemErrors); }); } return errors; } /** * Validates file configuration section */ function validateFileSection(section, path) { const errors = []; if (!section) return errors; // Validate required files if (section.required) { Object.entries(section.required).forEach(([key, config]) => { const fileErrors = validateFileConfig(config, `${path}.required.${key}`); errors.push(...fileErrors); }); } // Validate optional files if (section.optional) { Object.entries(section.optional).forEach(([key, config]) => { const fileErrors = validateFileConfig(config, `${path}.optional.${key}`); errors.push(...fileErrors); }); } return errors; } /** * Validates MCP server configuration */ function validateMcpServerConfig(config, options = {}) { const errors = []; const warnings = []; // Validate required fields if (!config.description) { errors.push({ path: 'description', message: 'Description is required' }); } if (!config.connection) { errors.push({ path: 'connection', message: 'Connection configuration is required' }); } else { const connectionErrors = validateConnection(config.connection, 'connection'); errors.push(...connectionErrors); } // Validate configuration sections if (config.config) { // Validate schema reference if (config.config.$schema && config.config.$schema !== 'https://schemas.aurracloud.com/server-config-v1.json') { warnings.push({ path: 'config.$schema', message: 'Schema reference should be "https://schemas.aurracloud.com/server-config-v1.json"', value: config.config.$schema }); } // Validate environment configuration const envErrors = validateConfigSection(config.config.environment, 'config.environment', options); errors.push(...envErrors); // Validate arguments configuration const argErrors = validateConfigSection(config.config.arguments, 'config.arguments', options); errors.push(...argErrors); // Validate files configuration const fileErrors = validateFileSection(config.config.files, 'config.files'); errors.push(...fileErrors); } // Validate capabilities if (config.capabilities) { const validCapabilities = ['tools', 'resources', 'prompts']; Object.keys(config.capabilities).forEach(key => { if (!validCapabilities.includes(key)) { warnings.push({ path: `capabilities.${key}`, message: `Unknown capability '${key}'. Valid capabilities are: ${validCapabilities.join(', ')}` }); } }); } return { valid: errors.length === 0, errors, warnings }; } /** * Validates package.json with MCP server configuration */ function validatePackageJsonWithMcp(packageJson, options = {}) { const errors = []; const warnings = []; // Validate required package.json fields if (!packageJson.name) { errors.push({ path: 'name', message: 'Package name is required' }); } if (!packageJson.version) { errors.push({ path: 'version', message: 'Package version is required' }); } // Validate MCP server configuration if (!packageJson.mcpServer) { errors.push({ path: 'mcpServer', message: 'MCP server configuration is required' }); } else { const mcpResult = validateMcpServerConfig(packageJson.mcpServer, options); errors.push(...mcpResult.errors.map(err => ({ ...err, path: `mcpServer.${err.path}` }))); warnings.push(...mcpResult.warnings.map(warn => ({ ...warn, path: `mcpServer.${warn.path}` }))); } return { valid: errors.length === 0, errors, warnings }; } /** * Creates default parse options */ function createDefaultParseOptions() { return { strict: false, allowUnknownProperties: true, validateFormats: true, resolveDefaults: true }; } //# sourceMappingURL=validator.js.map