#!/usr/bin/env node
/**
* Validation script to verify MCP Audio Inspector implementation
* Checks for:
* - Correct package structure
* - Required dependencies
* - Key functionality implementation
* - MCP server compliance
*/
import { promises as fs } from 'fs';
import path from 'path';
async function validateImplementation() {
console.log('🔍 Validating MCP Audio Inspector Implementation...\n');
const validations = [];
let passed = 0;
// Check 1: Package.json structure
try {
const packageJson = JSON.parse(await fs.readFile('./package.json', 'utf8'));
const requiredFields = ['name', 'version', 'type', 'main', 'bin', 'dependencies'];
const hasAllFields = requiredFields.every(field => packageJson[field]);
validations.push({
name: 'Package.json structure',
passed: hasAllFields && packageJson.type === 'module' && packageJson.name === 'mcp-audio-inspector',
details: hasAllFields ? 'All required fields present' : 'Missing required fields'
});
} catch (error) {
validations.push({
name: 'Package.json structure',
passed: false,
details: error.message
});
}
// Check 2: Required dependencies
try {
const packageJson = JSON.parse(await fs.readFile('./package.json', 'utf8'));
const deps = packageJson.dependencies || {};
const requiredDeps = ['music-metadata', '@modelcontextprotocol/sdk', 'commander'];
const hasAllDeps = requiredDeps.every(dep => deps[dep]);
validations.push({
name: 'Required dependencies',
passed: hasAllDeps,
details: hasAllDeps ? 'All dependencies present' : `Missing: ${requiredDeps.filter(d => !deps[d]).join(', ')}`
});
} catch (error) {
validations.push({
name: 'Required dependencies',
passed: false,
details: error.message
});
}
// Check 3: File structure
const requiredFiles = [
'./index.js',
'./lib/inspector.js',
'./README.md',
'./test/test.js'
];
for (const file of requiredFiles) {
try {
await fs.access(file);
validations.push({
name: `File exists: ${file}`,
passed: true,
details: 'File exists'
});
} catch (error) {
validations.push({
name: `File exists: ${file}`,
passed: false,
details: 'File missing'
});
}
}
// Check 4: Inspector class implementation
try {
const inspectorCode = await fs.readFile('./lib/inspector.js', 'utf8');
const requiredMethods = [
'analyzeFile',
'analyzeBatch',
'findAudioFiles',
'extractFormatInfo',
'extractTags',
'analyzeForGameAudio',
'getSupportedFormats'
];
const hasAllMethods = requiredMethods.every(method =>
inspectorCode.includes(`${method}(`) || inspectorCode.includes(`${method} (`)
);
validations.push({
name: 'AudioInspector class methods',
passed: hasAllMethods,
details: hasAllMethods ? 'All required methods present' : 'Missing required methods'
});
} catch (error) {
validations.push({
name: 'AudioInspector class methods',
passed: false,
details: error.message
});
}
// Check 5: MCP server tools
try {
const indexCode = await fs.readFile('./index.js', 'utf8');
const requiredTools = [
'analyze_audio_file',
'analyze_audio_batch',
'get_supported_formats'
];
const hasAllTools = requiredTools.every(tool => indexCode.includes(`'${tool}'`));
validations.push({
name: 'MCP server tools',
passed: hasAllTools,
details: hasAllTools ? 'All required tools implemented' : 'Missing required tools'
});
} catch (error) {
validations.push({
name: 'MCP server tools',
passed: false,
details: error.message
});
}
// Check 6: CLI functionality
try {
const indexCode = await fs.readFile('./index.js', 'utf8');
const hasStandalone = indexCode.includes('--standalone');
const hasBatch = indexCode.includes('--batch');
const hasCommander = indexCode.includes('commander');
validations.push({
name: 'CLI functionality',
passed: hasStandalone && hasBatch && hasCommander,
details: (hasStandalone && hasBatch && hasCommander) ? 'CLI options implemented' : 'Missing CLI features'
});
} catch (error) {
validations.push({
name: 'CLI functionality',
passed: false,
details: error.message
});
}
// Check 7: FFprobe fallback
try {
const inspectorCode = await fs.readFile('./lib/inspector.js', 'utf8');
const hasFFprobe = inspectorCode.includes('analyzeWithFFprobe') &&
inspectorCode.includes('ffprobe');
validations.push({
name: 'FFprobe fallback',
passed: hasFFprobe,
details: hasFFprobe ? 'FFprobe fallback implemented' : 'FFprobe fallback missing'
});
} catch (error) {
validations.push({
name: 'FFprobe fallback',
passed: false,
details: error.message
});
}
// Display results
console.log('Validation Results:\n');
validations.forEach((validation, index) => {
const icon = validation.passed ? '✅' : '❌';
console.log(`${icon} ${validation.name}`);
if (!validation.passed) {
console.log(` └─ ${validation.details}`);
}
if (validation.passed) passed++;
});
console.log(`\n📊 Results: ${passed}/${validations.length} validations passed`);
if (passed === validations.length) {
console.log('\n🎉 Implementation validation successful!');
console.log('The MCP Audio Inspector package appears to be correctly implemented.');
console.log('\nNext steps:');
console.log('1. Run: npm install');
console.log('2. Test: npm test');
console.log('3. Test standalone: npx mcp-audio-inspector --standalone <audio-file>');
console.log('4. Add to Claude Desktop configuration');
} else {
console.log('\n⚠️ Implementation has issues that need to be addressed.');
}
return passed === validations.length;
}
// Run validation if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
validateImplementation()
.then(success => {
process.exit(success ? 0 : 1);
})
.catch(error => {
console.error('Validation failed:', error);
process.exit(1);
});
}
export { validateImplementation };