Skip to main content
Glama
monitor.jsโ€ข8.91 kB
#!/usr/bin/env node import fs from 'fs/promises'; import path from 'path'; import { setTimeout } from 'timers/promises'; /** * Real-time monitoring tool for MCP Self-Learning Server * * Watches data files, logs, and system metrics */ class ServerMonitor { constructor(options = {}) { this.interval = options.interval || 5000; // 5 seconds this.showDetails = options.details || false; this.dataPath = path.join(process.cwd(), 'data'); this.logsPath = path.join(process.cwd(), 'logs'); this.running = true; this.lastData = { patterns: 0, knowledge: 0, learningCycles: 0, logSize: 0 }; } async start() { console.log('๐Ÿ“Š MCP Self-Learning Server Monitor'); console.log('==================================='); console.log(`๐Ÿ“ก Monitoring every ${this.interval/1000}s (Press Ctrl+C to stop)\n`); // Handle graceful shutdown process.on('SIGINT', () => { this.running = false; console.log('\n๐Ÿ‘‹ Monitor stopped'); process.exit(0); }); while (this.running) { await this.collectMetrics(); await setTimeout(this.interval); } } async collectMetrics() { try { const timestamp = new Date().toLocaleTimeString(); // Learning data metrics const learningData = await this.readLearningData(); // Log metrics const logMetrics = await this.readLogMetrics(); // System metrics const systemMetrics = this.getSystemMetrics(); // Display metrics console.clear(); console.log('๐Ÿ“Š MCP Self-Learning Server Monitor'); console.log('==================================='); console.log(`๐Ÿ•’ Last updated: ${timestamp}\n`); this.displayLearningMetrics(learningData); this.displayLogMetrics(logMetrics); this.displaySystemMetrics(systemMetrics); if (this.showDetails) { this.displayDetailedMetrics(learningData); } console.log('\n๐Ÿ’ก Press Ctrl+C to stop monitoring'); } catch (error) { console.error('โŒ Error collecting metrics:', error.message); } } async readLearningData() { try { const filePath = path.join(this.dataPath, 'learning-engine.json'); const content = await fs.readFile(filePath, 'utf8'); const data = JSON.parse(content); return { patterns: Array.isArray(data.patterns) ? data.patterns.length : 0, knowledge: Array.isArray(data.knowledge) ? data.knowledge.length : 0, learningCycles: data.metrics?.learningCycles || 0, totalInteractions: data.metrics?.totalInteractions || 0, successRate: data.metrics?.successRate || 0, averageResponseTime: data.metrics?.averageResponseTime || 0, lastSaved: new Date(data.timestamp).toLocaleString(), fileSize: content.length }; } catch (error) { return { patterns: 0, knowledge: 0, learningCycles: 0, totalInteractions: 0, successRate: 0, averageResponseTime: 0, lastSaved: 'Never', fileSize: 0, error: error.message }; } } async readLogMetrics() { try { const filePath = path.join(this.logsPath, 'mcp-server.log'); const stats = await fs.stat(filePath); const content = await fs.readFile(filePath, 'utf8'); const lines = content.split('\n').filter(line => line.trim()); // Count log levels const levels = { info: lines.filter(line => line.includes('INFO')).length, warn: lines.filter(line => line.includes('WARN')).length, error: lines.filter(line => line.includes('ERROR')).length, debug: lines.filter(line => line.includes('DEBUG')).length }; return { fileSize: Math.round(stats.size / 1024 * 10) / 10, // KB lines: lines.length, lastModified: stats.mtime.toLocaleString(), levels }; } catch (error) { return { fileSize: 0, lines: 0, lastModified: 'Never', levels: { info: 0, warn: 0, error: 0, debug: 0 }, error: error.message }; } } getSystemMetrics() { const usage = process.memoryUsage(); const uptime = process.uptime(); return { memoryUsage: { rss: Math.round(usage.rss / 1024 / 1024 * 10) / 10, heapUsed: Math.round(usage.heapUsed / 1024 / 1024 * 10) / 10, heapTotal: Math.round(usage.heapTotal / 1024 / 1024 * 10) / 10 }, uptime: { seconds: Math.round(uptime), formatted: this.formatUptime(uptime) } }; } displayLearningMetrics(data) { console.log('๐Ÿง  Learning Engine Status:'); console.log(` Patterns: ${data.patterns} ${this.getChangeIndicator('patterns', data.patterns)}`); console.log(` Knowledge Items: ${data.knowledge} ${this.getChangeIndicator('knowledge', data.knowledge)}`); console.log(` Learning Cycles: ${data.learningCycles} ${this.getChangeIndicator('learningCycles', data.learningCycles)}`); console.log(` Total Interactions: ${data.totalInteractions}`); console.log(` Success Rate: ${(data.successRate * 100).toFixed(1)}%`); console.log(` Avg Response: ${data.averageResponseTime}ms`); console.log(` Last Saved: ${data.lastSaved}`); console.log(` Data File Size: ${Math.round(data.fileSize / 1024 * 10) / 10}KB`); if (data.error) { console.log(` โŒ Error: ${data.error}`); } console.log(''); } displayLogMetrics(data) { console.log('๐Ÿ“ Logging Status:'); console.log(` Log File Size: ${data.fileSize}KB ${this.getChangeIndicator('logSize', data.fileSize)}`); console.log(` Total Lines: ${data.lines}`); console.log(` Last Modified: ${data.lastModified}`); console.log(` Log Levels: INFO:${data.levels.info} WARN:${data.levels.warn} ERROR:${data.levels.error} DEBUG:${data.levels.debug}`); if (data.error) { console.log(` โŒ Error: ${data.error}`); } console.log(''); } displaySystemMetrics(data) { console.log('๐Ÿ’ป System Metrics:'); console.log(` Memory (RSS): ${data.memoryUsage.rss}MB`); console.log(` Memory (Heap): ${data.memoryUsage.heapUsed}MB / ${data.memoryUsage.heapTotal}MB`); console.log(` Monitor Uptime: ${data.uptime.formatted}`); console.log(''); } displayDetailedMetrics(data) { console.log('๐Ÿ“‹ Detailed Information:'); console.log(' Recent Activity:'); // Show changes since last check Object.keys(this.lastData).forEach(key => { if (data[key] !== this.lastData[key] && data[key] !== undefined) { const change = data[key] - this.lastData[key]; const sign = change > 0 ? '+' : ''; console.log(` ${key}: ${sign}${change}`); } }); if (Object.keys(this.lastData).every(key => data[key] === this.lastData[key])) { console.log(' No changes detected'); } console.log(''); } getChangeIndicator(key, currentValue) { const lastValue = this.lastData[key]; const change = currentValue - lastValue; if (change > 0) { this.lastData[key] = currentValue; return `(+${change})`; } else if (change < 0) { this.lastData[key] = currentValue; return `(${change})`; } this.lastData[key] = currentValue; return ''; } formatUptime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); if (hours > 0) { return `${hours}h ${minutes}m ${secs}s`; } else if (minutes > 0) { return `${minutes}m ${secs}s`; } else { return `${secs}s`; } } } // CLI interface async function main() { const args = process.argv.slice(2); const options = { interval: 5000, details: false }; // Parse command line arguments for (let i = 0; i < args.length; i++) { switch (args[i]) { case '--interval': case '-i': options.interval = parseInt(args[++i]) * 1000; break; case '--details': case '-d': options.details = true; break; case '--help': case '-h': console.log('MCP Server Monitor\n'); console.log('Usage: node monitor.js [options]\n'); console.log('Options:'); console.log(' -i, --interval <seconds> Monitoring interval (default: 5)'); console.log(' -d, --details Show detailed metrics'); console.log(' -h, --help Show this help'); process.exit(0); } } const monitor = new ServerMonitor(options); await monitor.start(); } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { await main(); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/saralegui-solutions/mcp-self-learning-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server