#!/usr/bin/env node
import { spawn } from 'child_process';
import { setTimeout } from 'timers/promises';
/**
* Health Check Tool for MCP Self-Learning Server
*
* Tests server functionality and reports status
*/
class HealthCheck {
constructor() {
this.results = {
startup: false,
tools: {},
persistence: false,
logging: false,
performance: {}
};
}
async run() {
console.log('๐ฅ MCP Self-Learning Server Health Check\n');
await this.checkStartup();
await this.checkPersistence();
await this.checkLogging();
await this.checkPerformance();
this.printResults();
// Ensure output is flushed before exit
await new Promise(resolve => setTimeout(resolve, 100));
process.exit(this.allPassed() ? 0 : 1);
}
async checkStartup() {
console.log('๐ Testing server startup...');
try {
const server = spawn('node', ['mcp-self-learning-server.js'], {
stdio: 'pipe',
cwd: process.cwd()
});
let output = '';
server.stdout.on('data', (data) => {
output += data.toString();
});
server.stderr.on('data', (data) => {
output += data.toString();
});
// Wait for server to start
await setTimeout(3000);
// Send SIGTERM to shut down
server.kill('SIGTERM');
// Wait for process to exit
await new Promise((resolve) => {
server.on('exit', resolve);
});
if (output.includes('MCP Self-Learning Server started') &&
output.includes('Learning engine initialized')) {
this.results.startup = true;
console.log(' โ
Server startup successful');
} else {
console.log(' โ Server startup failed');
console.log(' Output:', output.substring(0, 200));
}
} catch (error) {
console.log(' โ Server startup error:', error.message);
}
}
async checkPersistence() {
console.log('\n๐พ Testing data persistence...');
try {
const fs = await import('fs/promises');
const path = await import('path');
const dataDir = path.join(process.cwd(), 'data');
const learningFile = path.join(dataDir, 'learning-engine.json');
// Check if data directory exists
try {
await fs.access(dataDir);
console.log(' โ
Data directory exists');
// Check if learning data file exists
try {
await fs.access(learningFile);
const content = await fs.readFile(learningFile, 'utf8');
const data = JSON.parse(content);
if (data.patterns && data.knowledge && data.metrics) {
this.results.persistence = true;
console.log(' โ
Learning data file valid');
console.log(` - Patterns: ${Array.isArray(data.patterns) ? data.patterns.length : 0}`);
console.log(` - Knowledge entries: ${Array.isArray(data.knowledge) ? data.knowledge.length : 0}`);
console.log(` - Learning cycles: ${data.metrics?.learningCycles || 0}`);
} else {
console.log(' โ Learning data file structure invalid');
}
} catch (error) {
console.log(' โ ๏ธ Learning data file not found (expected on first run)');
this.results.persistence = true; // Not an error on first run
}
} catch (error) {
console.log(' โ Data directory not accessible');
}
} catch (error) {
console.log(' โ Persistence check error:', error.message);
}
}
async checkLogging() {
console.log('\n๐ Testing logging system...');
try {
const fs = await import('fs/promises');
const path = await import('path');
const logsDir = path.join(process.cwd(), 'logs');
const logFile = path.join(logsDir, 'mcp-server.log');
// Check if logs directory exists
try {
await fs.access(logsDir);
console.log(' โ
Logs directory exists');
// Check if log file exists
try {
await fs.access(logFile);
const stats = await fs.stat(logFile);
if (stats.size > 0) {
this.results.logging = true;
console.log(' โ
Log file exists and has content');
console.log(` - File size: ${Math.round(stats.size / 1024 * 10) / 10}KB`);
console.log(` - Modified: ${stats.mtime.toLocaleString()}`);
} else {
console.log(' โ ๏ธ Log file exists but is empty');
}
} catch (error) {
console.log(' โ ๏ธ Log file not found');
}
} catch (error) {
console.log(' โ ๏ธ Logs directory not found');
}
} catch (error) {
console.log(' โ Logging check error:', error.message);
}
}
async checkPerformance() {
console.log('\nโก Testing performance...');
try {
const startTime = process.hrtime.bigint();
// Test server startup time
const server = spawn('node', ['mcp-self-learning-server.js'], {
stdio: 'pipe',
cwd: process.cwd()
});
let startupComplete = false;
server.stdout.on('data', (data) => {
if (data.toString().includes('MCP Self-Learning Server started') && !startupComplete) {
const endTime = process.hrtime.bigint();
const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
this.results.performance.startupTime = duration;
startupComplete = true;
if (duration < 5000) { // Less than 5 seconds
console.log(` โ
Startup time: ${Math.round(duration)}ms`);
} else {
console.log(` โ ๏ธ Slow startup time: ${Math.round(duration)}ms`);
}
// Shut down the server
server.kill('SIGTERM');
}
});
// Wait for startup or timeout
await setTimeout(10000);
if (!startupComplete) {
console.log(' โ Server startup timeout (>10s)');
server.kill('SIGKILL');
}
// Wait for process to exit
await new Promise((resolve) => {
server.on('exit', resolve);
});
// Check memory usage
const memUsage = process.memoryUsage();
this.results.performance.memoryUsage = {
rss: Math.round(memUsage.rss / 1024 / 1024),
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024)
};
console.log(` ๐ Health check memory usage: ${this.results.performance.memoryUsage.heapUsed}MB heap`);
} catch (error) {
console.log(' โ Performance check error:', error.message);
}
}
printResults() {
console.log('\n๐ Health Check Results:');
console.log('========================');
const status = (passed) => passed ? 'โ
PASS' : 'โ FAIL';
console.log(`Startup: ${status(this.results.startup)}`);
console.log(`Persistence: ${status(this.results.persistence)}`);
console.log(`Logging: ${status(this.results.logging)}`);
if (this.results.performance.startupTime) {
const perfStatus = this.results.performance.startupTime < 5000 ? 'โ
GOOD' : 'โ ๏ธ SLOW';
console.log(`Performance: ${perfStatus} (${Math.round(this.results.performance.startupTime)}ms startup)`);
}
console.log('\n๐ฏ Overall Status:', this.allPassed() ? 'โ
HEALTHY' : 'โ ISSUES DETECTED');
if (!this.allPassed()) {
console.log('\n๐ก Recommendations:');
if (!this.results.startup) {
console.log(' - Check server dependencies and configuration');
}
if (!this.results.persistence) {
console.log(' - Verify file system permissions for data directory');
}
if (!this.results.logging) {
console.log(' - Check logging configuration and permissions');
}
}
}
allPassed() {
return this.results.startup && this.results.persistence && this.results.logging;
}
}
// Run health check if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
const healthCheck = new HealthCheck();
healthCheck.run().catch((error) => {
console.error('Health check failed:', error);
process.exit(1);
});
}