enhanced-error-handler.js•8.42 kB
import { ToolError, ToolErrorHandler } from './error-handling.js';
export class EnhancedErrorHandler extends ToolErrorHandler {
constructor(toolName = 'unknown') {
super(toolName);
this.toolName = toolName;
this.startTime = Date.now();
}
/**
* Enhanced error handling with logging and clear feedback
*/
handleErrorWithFeedback(error, context = {}) {
const startTime = this.startTime;
const duration = Date.now() - startTime;
// Create failure context for analysis
const loggedFailure = {
toolName: this.toolName,
error: {
code: error.code || 'UNKNOWN',
message: error.message
},
context: {
...context,
duration,
toolName: this.toolName
},
timestamp: new Date().toISOString()
};
// Get enhanced error details
const enhancedError = this.enhanceErrorDetails(error, loggedFailure);
return enhancedError;
}
/**
* Enhance error with additional context and suggestions
*/
enhanceErrorDetails(error, loggedFailure) {
// Use existing error handling as base
const baseError = this.handleError(error);
// Add failure analysis
const analysis = this.analyzeFailure(error, loggedFailure);
// Generate contextual suggestions
const suggestions = this.generateContextualSuggestions(error, loggedFailure, baseError);
// Create enhanced error response
const enhancedResponse = {
success: false,
error: {
...baseError.toJSON(),
analysis: analysis,
suggestions: suggestions,
failureId: this.generateFailureId(),
timestamp: new Date().toISOString()
},
nextSteps: this.generateNextSteps(error, loggedFailure)
};
return enhancedResponse;
}
/**
* Analyze failure patterns and root causes
*/
analyzeFailure(error, loggedFailure) {
const analysis = {
severity: this.determineSeverity(error),
category: this.categorizeError(error),
likelyCauses: this.identifyLikelyCauses(error),
frequency: this.checkFrequency(loggedFailure.toolName, error.code),
systemContext: this.getSystemContext()
};
return analysis;
}
determineSeverity(error) {
if (error.code === 'ENOENT' || error.code === 'EACCES') {
return 'high';
}
if (error.message.includes('timeout') || error.message.includes('connection')) {
return 'medium';
}
if (error.message.includes('not found') || error.message.includes('invalid')) {
return 'low';
}
return 'medium';
}
categorizeError(error) {
if (error.code === 'ENOENT' || error.message.includes('no such file')) {
return 'file_system';
}
if (error.code === 'EACCES' || error.message.includes('permission')) {
return 'permissions';
}
if (error.message.includes('timeout') || error.message.includes('connection')) {
return 'connectivity';
}
if (error.message.includes('memory') || error.message.includes('resource')) {
return 'resource';
}
return 'general';
}
identifyLikelyCauses(error) {
const causes = [];
if (error.code === 'ENOENT') {
causes.push('File or directory does not exist');
causes.push('Incorrect path provided');
causes.push('Working directory changed unexpectedly');
}
if (error.message.includes('timeout')) {
causes.push('Operation took too long to complete');
causes.push('System is under heavy load');
causes.push('Large files or complex operations');
}
if (error.message.includes('connection')) {
causes.push('Network connectivity issues');
causes.push('MCP server connection problems');
causes.push('External service unavailable');
}
if (error.message.includes('permission')) {
causes.push('Insufficient file permissions');
causes.push('User access restrictions');
causes.push('Security policies blocking access');
}
return causes.length > 0 ? causes : ['Unknown cause - need further investigation'];
}
checkFrequency(toolName, errorCode) {
// Simplified frequency check - always return 'rare' since we removed failureLogger
return 'rare';
}
getSystemContext() {
return {
nodeVersion: process.version,
platform: process.platform,
memoryUsage: process.memoryUsage(),
uptime: process.uptime()
};
}
generateContextualSuggestions(error, loggedFailure, baseError = null) {
const suggestions = [];
// Add base error suggestions if available
if (baseError && baseError.suggestions) {
suggestions.push(...baseError.suggestions);
}
// Add contextual suggestions based on error type
if (error.code === 'ENOENT') {
suggestions.push('Check if the working directory path is correct');
suggestions.push('Verify the file exists in the expected location');
suggestions.push('Use absolute paths instead of relative paths');
}
if (error.message.includes('timeout')) {
suggestions.push('Try breaking the operation into smaller chunks');
suggestions.push('Increase timeout if the operation is legitimately long-running');
suggestions.push('Check if the system is under heavy load');
}
if (loggedFailure.context.pattern) {
suggestions.push('Try modifying your AST pattern to be more specific');
suggestions.push('Consider using simpler patterns first');
}
return suggestions;
}
generateNextSteps(error, loggedFailure) {
const nextSteps = [];
// Always suggest checking the logs
nextSteps.push('Check the MCP failure logs for detailed analysis');
// Add tool-specific next steps
if (loggedFailure.toolName.includes('ast')) {
nextSteps.push('Verify your AST pattern syntax is correct');
nextSteps.push('Try simpler patterns first');
}
if (loggedFailure.toolName.includes('execute')) {
nextSteps.push('Check your command syntax and parameters');
nextSteps.push('Verify the working directory is accessible');
}
// Add recovery steps based on frequency
const frequency = this.checkFrequency(loggedFailure.toolName, error.code);
if (frequency === 'frequent') {
nextSteps.push('This error is occurring frequently - consider restarting the MCP server');
nextSteps.push('Check for systemic issues in your environment');
}
return nextSteps;
}
generateFailureId() {
return `failure_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Create user-friendly error message for MCP response
*/
createErrorResponse(error, context = {}) {
const enhancedError = this.handleErrorWithFeedback(error, context);
// Format for MCP response
const userMessage = this.formatUserMessage(enhancedError);
return {
content: [{
type: "text",
text: userMessage
}],
isError: true,
metadata: {
failureId: enhancedError.error.failureId,
severity: enhancedError.error.analysis.severity,
category: enhancedError.error.analysis.category
}
};
}
formatUserMessage(enhancedError) {
const error = enhancedError.error;
const analysis = error.analysis;
let message = `🚨 **${error.tool.toUpperCase()} TOOL FAILURE**\n\n`;
message += `**Error:** ${error.message}\n`;
message += `**Type:** ${error.code} (Severity: ${analysis.severity})\n\n`;
if (analysis.likelyCauses.length > 0) {
message += `**Likely Causes:**\n`;
analysis.likelyCauses.forEach((cause, index) => {
message += `${index + 1}. ${cause}\n`;
});
message += '\n';
}
if (enhancedError.suggestions.length > 0) {
message += `**Suggestions:**\n`;
enhancedError.suggestions.forEach((suggestion, index) => {
message += `${index + 1}. ${suggestion}\n`;
});
message += '\n';
}
if (enhancedError.nextSteps.length > 0) {
message += `**Next Steps:**\n`;
enhancedError.nextSteps.forEach((step, index) => {
message += `${index + 1}. ${step}\n`;
});
message += '\n';
}
message += `**Failure ID:** ${error.failureId}\n`;
message += `**Check logs:** \`glootie/mcp-failures.log\` for detailed analysis\n`;
return message;
}
}
export function createEnhancedErrorHandler(toolName) {
return new EnhancedErrorHandler(toolName);
}