hana-cli
Version:
HANA Developer Command Line Interface
171 lines (142 loc) • 5.99 kB
JavaScript
/**
* MCP Server Validation Test
*
* This script tests that the MCP server properly:
* 1. Loads all commands from the CLI
* 2. Extracts their parameters correctly
* 3. Exposes them with proper schemas
* 4. Handles function-based builders
*
* Usage: node test-mcp-validation.js
*/
import { fileURLToPath, pathToFileURL } from 'url';
import { dirname, join } from 'path';
import { extractCommandInfo } from './build/command-parser.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
async function validateMcpServer() {
console.log('=== MCP Server Validation ===\n');
try {
// Load commands
console.log('1. Loading commands from CLI...');
const indexPath = join(__dirname, '..', 'bin', 'index.js');
const indexUrl = pathToFileURL(indexPath).href;
const indexModule = await import(indexUrl);
if (typeof indexModule.init !== 'function') {
throw new Error('index.js does not export an init() function');
}
const commands = await indexModule.init();
console.log(` ✓ Loaded ${commands.length} command modules\n`);
// Analyze commands
console.log('2. Analyzing command parameters...\n');
const stats = {
total: 0,
withParameters: 0,
withAliases: 0,
functionBuilders: 0,
objectBuilders: 0,
noBuilder: 0,
missingDescription: 0
};
const commandsByType = [];
let sampleCommands = [];
for (const cmd of commands) {
if (!cmd || typeof cmd.command !== 'string') continue;
stats.total++;
const commandName = cmd.command.split(' ')[0];
// Analyze builder type
if (!cmd.builder) {
stats.noBuilder++;
} else if (typeof cmd.builder === 'function') {
stats.functionBuilders++;
} else if (typeof cmd.builder === 'object') {
stats.objectBuilders++;
}
// Extract info like the MCP server does
const info = extractCommandInfo(cmd);
if (Object.keys(info.schema?.properties || {}).length > 0) {
stats.withParameters++;
}
if (info.aliases && info.aliases.length > 0) {
stats.withAliases++;
}
if (!info.description || info.description.startsWith('Execute')) {
stats.missingDescription++;
}
// Collect sample commands with interesting parameters
if (sampleCommands.length < 5 && Object.keys(info.schema?.properties || {}).length > 2) {
sampleCommands.push({
name: commandName,
aliases: info.aliases,
description: info.description,
parameterCount: Object.keys(info.schema?.properties || {}).length,
parameters: Object.keys(info.schema?.properties || {}).slice(0, 5)
});
}
}
// Print statistics
console.log(' Statistics:');
console.log(` - Total commands: ${stats.total}`);
console.log(` - With parameters: ${stats.withParameters} (${((stats.withParameters/stats.total)*100).toFixed(1)}%)`);
console.log(` - With aliases: ${stats.withAliases} (${((stats.withAliases/stats.total)*100).toFixed(1)}%)`);
console.log(` - Object builders: ${stats.objectBuilders}`);
console.log(` - Function builders: ${stats.functionBuilders}`);
console.log(` - No builder: ${stats.noBuilder}`);
console.log(` - Missing descriptions: ${stats.missingDescription}\n`);
// Show sample commands
console.log('3. Sample commands with parameters:\n');
for (const cmd of sampleCommands) {
console.log(` Command: ${cmd.name}`);
if (cmd.aliases.length > 0) {
console.log(` Aliases: ${cmd.aliases.join(', ')}`);
}
console.log(` Description: ${cmd.description}`);
console.log(` Parameters (${cmd.parameterCount}): ${cmd.parameters.join(', ')}`);
console.log('');
}
// Test specific important commands
console.log('4. Verifying key commands are exposed:\n');
const keyCommands = ['import', 'export', 'tables', 'schemas', 'status', 'version'];
const commandMap = new Map();
for (const cmd of commands) {
if (cmd && typeof cmd.command === 'string') {
const commandName = cmd.command.split(' ')[0];
commandMap.set(commandName, cmd);
}
}
for (const keyCmd of keyCommands) {
if (commandMap.has(keyCmd)) {
const cmd = commandMap.get(keyCmd);
const info = extractCommandInfo(cmd);
const paramCount = Object.keys(info.schema?.properties || {}).length;
console.log(` ✓ ${keyCmd}: ${paramCount} parameters${info.aliases.length > 0 ? ` (aliases: ${info.aliases.join(', ')})` : ''}`);
} else {
console.log(` ✗ ${keyCmd}: NOT FOUND`);
}
}
// Test import command specifically (should have new parameters)
console.log('\n5. Checking import command enhancements:\n');
const importCmd = commandMap.get('import');
if (importCmd) {
const info = extractCommandInfo(importCmd);
const params = info.schema?.properties || {};
const newParams = ['matchMode', 'dryRun', 'maxFileSizeMB', 'timeoutSeconds', 'nullValues', 'skipWithErrors', 'maxErrorsAllowed'];
for (const param of newParams) {
if (params[param]) {
const paramInfo = params[param];
console.log(` ✓ ${param}: ${paramInfo.type}${paramInfo.enum ? ` (choices: ${paramInfo.enum.join(', ')})` : ''}${paramInfo.default !== undefined ? ` (default: ${paramInfo.default})` : ''}`);
} else {
console.log(` ? ${param}: NOT FOUND`);
}
}
}
console.log('\n=== Validation Complete ===');
console.log(`✓ MCP Server is properly configured with ${stats.total} commands\n`);
} catch (error) {
console.error('❌ Validation failed:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
// Run validation
validateMcpServer().catch(console.error);