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