loganalyzer-mcp
Version:
🚀 Debug server logs in under 30 seconds - AI-powered MCP server with rapid debugging, real-time monitoring, and actionable fixes
396 lines • 16 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
import { LogAnalyzer } from './tools/logAnalyzer.js';
import { FileWatcher } from './tools/fileWatcher.js';
import { RapidDebugger } from './tools/rapidDebugger.js';
class LogAnalyzerMCPServer {
server;
logAnalyzer;
fileWatcher;
rapidDebugger;
constructor() {
this.server = new Server({
name: 'loganalyzer-mcp',
version: '1.0.0',
description: 'AI-powered log analysis MCP server with rapid debugging - debug server logs in under 30 seconds'
}, {
capabilities: {
tools: {},
resources: {},
logging: {}
}
});
this.logAnalyzer = new LogAnalyzer();
this.fileWatcher = new FileWatcher();
this.rapidDebugger = new RapidDebugger();
this.setupHandlers();
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'rapid_debug',
description: '🚀 DEBUG SERVER LOGS IN UNDER 30 SECONDS - Instant analysis with actionable fixes and debug commands',
inputSchema: {
type: 'object',
properties: {
logText: {
type: 'string',
description: 'Log content to rapidly analyze and debug'
}
},
required: ['logText']
}
},
{
name: 'quick_scan',
description: 'âš¡ Ultra-fast log scan for real-time monitoring (< 1 second)',
inputSchema: {
type: 'object',
properties: {
logText: {
type: 'string',
description: 'Log content for quick error detection'
}
},
required: ['logText']
}
},
{
name: 'analyze_log',
description: 'Analyze error logs and provide root cause analysis with AI-powered insights',
inputSchema: {
type: 'object',
properties: {
logText: {
type: 'string',
description: 'Log content to analyze'
},
logFormat: {
type: 'string',
enum: ['auto', 'json', 'plain'],
default: 'auto',
description: 'Format of the log content'
},
contextLines: {
type: 'number',
default: 50,
description: 'Number of context lines to include around errors'
}
},
required: ['logText']
}
},
{
name: 'watch_log_file',
description: 'Start monitoring a log file for real-time error detection',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the log file to monitor'
},
pollInterval: {
type: 'number',
default: 1000,
description: 'Polling interval in milliseconds'
}
},
required: ['filePath']
}
},
{
name: 'stop_watching',
description: 'Stop monitoring a specific log file',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the log file to stop monitoring'
}
},
required: ['filePath']
}
},
{
name: 'list_watched_files',
description: 'List all currently monitored log files',
inputSchema: {
type: 'object',
properties: {}
}
},
{
name: 'get_recent_errors',
description: 'Get recent error analysis from monitored files',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Optional: specific file path to get errors from'
},
limit: {
type: 'number',
default: 10,
description: 'Maximum number of recent errors to return'
}
}
}
}
]
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
let result;
switch (name) {
case 'rapid_debug':
result = await this.handleRapidDebug(args);
break;
case 'quick_scan':
result = await this.handleQuickScan(args);
break;
case 'analyze_log':
result = await this.handleAnalyzeLog(args);
break;
case 'watch_log_file':
result = await this.handleWatchLogFile(args);
break;
case 'stop_watching':
result = await this.handleStopWatching(args);
break;
case 'list_watched_files':
result = await this.handleListWatchedFiles(args);
break;
case 'get_recent_errors':
result = await this.handleGetRecentErrors(args);
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
}, null, 2)
}
],
isError: true
};
}
});
// List available resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'loganalyzer://rapid-debug',
name: 'Rapid Debug Results',
description: 'Latest rapid debugging analysis with quick fixes'
},
{
uri: 'loganalyzer://recent-errors',
name: 'Recent Error Analysis',
description: 'Latest analyzed errors from all monitored files'
},
{
uri: 'loganalyzer://watched-files',
name: 'Watched Files Status',
description: 'Status of all currently monitored log files'
}
]
};
});
// Handle resource reading
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
switch (uri) {
case 'loganalyzer://rapid-debug':
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify({
message: 'Use rapid_debug tool for instant server log debugging',
features: [
'Debug in under 30 seconds',
'Instant error classification',
'Ready-to-run debug commands',
'Prioritized quick fixes'
]
}, null, 2)
}
]
};
case 'loganalyzer://recent-errors':
const recentErrors = await this.fileWatcher.getRecentErrors();
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify(recentErrors, null, 2)
}
]
};
case 'loganalyzer://watched-files':
const watchedFiles = await this.fileWatcher.listWatchedFiles();
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify(watchedFiles, null, 2)
}
]
};
default:
throw new Error(`Unknown resource: ${uri}`);
}
});
}
async handleRapidDebug(args) {
const { logText } = args;
if (!logText || typeof logText !== 'string') {
throw new Error('logText is required and must be a string');
}
const startTime = Date.now();
const debugResult = await this.rapidDebugger.debugInUnder30Seconds(logText);
const totalTime = Date.now() - startTime;
return {
success: true,
data: {
...debugResult,
totalProcessingTime: totalTime,
message: `🚀 Server debugging completed in ${debugResult.timeToAnalysis}ms`,
under30Seconds: debugResult.timeToAnalysis < 30000
},
metadata: {
processedAt: new Date(),
logLength: logText.length,
debugMode: 'rapid'
}
};
}
async handleQuickScan(args) {
const { logText } = args;
if (!logText || typeof logText !== 'string') {
throw new Error('logText is required and must be a string');
}
const scanResult = await this.rapidDebugger.quickScan(logText);
return {
success: true,
data: {
...scanResult,
message: `âš¡ Quick scan completed in ${scanResult.time}ms`
},
metadata: {
processedAt: new Date(),
scanMode: 'quick'
}
};
}
async handleAnalyzeLog(args) {
const { logText, logFormat = 'auto', contextLines = 50 } = args;
if (!logText || typeof logText !== 'string') {
throw new Error('logText is required and must be a string');
}
const analysis = await this.logAnalyzer.analyzeLogs(logText, {
logFormat,
contextLines
});
return {
success: true,
data: analysis,
metadata: {
processedAt: new Date(),
logLength: logText.length,
format: logFormat
}
};
}
async handleWatchLogFile(args) {
const { filePath, pollInterval = 1000 } = args;
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath is required and must be a string');
}
await this.fileWatcher.watchLogFile(filePath, { pollInterval });
return {
success: true,
data: {
message: `Started watching ${filePath}`,
filePath,
pollInterval
}
};
}
async handleStopWatching(args) {
const { filePath } = args;
if (!filePath || typeof filePath !== 'string') {
throw new Error('filePath is required and must be a string');
}
await this.fileWatcher.stopWatching(filePath);
return {
success: true,
data: {
message: `Stopped watching ${filePath}`,
filePath
}
};
}
async handleListWatchedFiles(args) {
const watchedFiles = await this.fileWatcher.listWatchedFiles();
return {
success: true,
data: watchedFiles
};
}
async handleGetRecentErrors(args) {
const { filePath, limit = 10 } = args;
const recentErrors = await this.fileWatcher.getRecentErrors(filePath, limit);
return {
success: true,
data: recentErrors
};
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('LogAnalyzer MCP Server started successfully - Debug server logs in under 30 seconds!');
}
}
// Start the server
async function main() {
const server = new LogAnalyzerMCPServer();
await server.start();
}
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch((error) => {
console.error('Failed to start server:', error);
process.exit(1);
});
}
//# sourceMappingURL=server.js.map