Skip to main content
Glama
operation-error-handler.ts14.7 kB
/** * Operation Error Handler * * Provides detailed error messages with configuration guidance. * Handles different types of errors and provides actionable solutions. */ export interface ErrorResponse { error: { code: string; message: string; details?: any; suggestions: string[]; configurationGuide?: { requiredEnvVars: string[]; exampleConfig: Record<string, string>; setupInstructions: string[]; }; }; } export interface ToolResult { success: boolean; data?: any; error?: { code: string; message: string; details?: any; suggestions?: string[]; }; metadata?: { provider?: string; operation: string; timestamp: string; executionTime: number; }; } export class OperationErrorHandler { /** * Creates a standardized error response */ public static createErrorResponse( code: string, message: string, details?: any, suggestions: string[] = [] ): ErrorResponse { return { error: { code, message, details, suggestions, }, }; } /** * Creates a tool result with error information */ public static createToolError( code: string, message: string, operation: string, details?: any, suggestions: string[] = [] ): ToolResult { return { success: false, error: { code, message, details, suggestions, }, metadata: { operation, timestamp: new Date().toISOString(), executionTime: 0, }, }; } /** * Handles configuration errors with setup guidance */ public static handleConfigurationError( provider?: 'github' | 'gitea' | 'both', operation?: string ): ErrorResponse { const response = this.createErrorResponse( 'CONFIGURATION_ERROR', 'Provider configuration is missing or invalid', { provider, operation } ); if (provider === 'github' || provider === 'both') { response.error.suggestions.push('Configure GitHub: Set GITHUB_TOKEN and GITHUB_USERNAME environment variables'); } if (provider === 'gitea' || provider === 'both') { response.error.suggestions.push('Configure Gitea: Set GITEA_URL, GITEA_TOKEN, and GITEA_USERNAME environment variables'); } response.error.configurationGuide = { requiredEnvVars: this.getRequiredEnvVars(provider), exampleConfig: this.getExampleConfig(provider), setupInstructions: this.getSetupInstructions(provider), }; return response; } /** * Handles validation errors with parameter guidance */ public static handleValidationError( errors: string[], suggestions: string[] = [], toolName?: string, action?: string ): ErrorResponse { const response = this.createErrorResponse( 'VALIDATION_ERROR', `Parameter validation failed: ${errors.join(', ')}`, { toolName, action, validationErrors: errors }, suggestions ); // Add general parameter guidance response.error.suggestions.push('Ensure all required parameters are provided'); response.error.suggestions.push('Check parameter formats and types'); if (toolName && action) { response.error.suggestions.push(`See documentation for ${toolName} ${action} parameters`); } return response; } /** * Handles Git command errors */ public static handleGitError( gitError: string, operation: string, projectPath?: string ): ToolResult { let code = 'GIT_ERROR'; let message = `Git operation failed: ${gitError}`; const suggestions: string[] = []; // Analyze common Git errors and provide specific guidance if (gitError.includes('not a git repository')) { code = 'NOT_GIT_REPOSITORY'; message = 'The specified directory is not a Git repository'; suggestions.push('Initialize a Git repository with: git init'); suggestions.push('Or navigate to an existing Git repository'); } else if (gitError.includes('nothing to commit')) { code = 'NOTHING_TO_COMMIT'; message = 'No changes to commit'; suggestions.push('Make changes to files before committing'); suggestions.push('Use git status to see current repository state'); } else if (gitError.includes('merge conflict')) { code = 'MERGE_CONFLICT'; message = 'Merge conflict detected'; suggestions.push('Resolve conflicts in the affected files'); suggestions.push('Use git status to see conflicted files'); suggestions.push('After resolving, use git add and git commit'); } else if (gitError.includes('remote origin already exists')) { code = 'REMOTE_EXISTS'; message = 'Remote origin already exists'; suggestions.push('Use git remote set-url origin <url> to change the remote URL'); suggestions.push('Or use git remote remove origin to remove the existing remote'); } else if (gitError.includes('Permission denied')) { code = 'PERMISSION_DENIED'; message = 'Permission denied for Git operation'; suggestions.push('Check your SSH keys or authentication credentials'); suggestions.push('Ensure you have write access to the repository'); } else if (gitError.includes('branch already exists')) { code = 'BRANCH_EXISTS'; message = 'Branch already exists'; suggestions.push('Use a different branch name'); suggestions.push('Or delete the existing branch first'); suggestions.push('Check existing branches with: git branch -a'); } else if (gitError.includes('branch not found') || gitError.includes('not found in upstream')) { code = 'BRANCH_NOT_FOUND'; message = 'Branch not found'; suggestions.push('Check if the branch name is correct'); suggestions.push('Use git branch -a to see all available branches'); suggestions.push('Ensure the branch exists on the remote repository'); } else if (gitError.includes('cannot lock ref')) { code = 'REF_LOCK_ERROR'; message = 'Cannot lock Git reference'; suggestions.push('Another Git operation might be in progress'); suggestions.push('Wait for other operations to complete'); suggestions.push('If stuck, try: git gc --prune=now'); } else if (gitError.includes('detached HEAD')) { code = 'DETACHED_HEAD'; message = 'Repository is in detached HEAD state'; suggestions.push('Create a new branch: git checkout -b <branch-name>'); suggestions.push('Or switch to an existing branch: git checkout <branch-name>'); suggestions.push('Or merge to main: git checkout main && git merge <commit-hash>'); } else if (gitError.includes('working tree is dirty')) { code = 'DIRTY_WORKING_TREE'; message = 'Working directory has uncommitted changes'; suggestions.push('Commit your changes: git add . && git commit -m "message"'); suggestions.push('Or stash your changes: git stash'); suggestions.push('Or discard changes: git checkout -- .'); } else if (gitError.includes('upstream branch')) { code = 'UPSTREAM_BRANCH_ERROR'; message = 'Upstream branch configuration issue'; suggestions.push('Set upstream branch: git branch --set-upstream-to=origin/<branch>'); suggestions.push('Or push with upstream: git push --set-upstream origin <branch>'); } else if (gitError.includes('fast-forward')) { code = 'FAST_FORWARD_ERROR'; message = 'Cannot fast-forward merge'; suggestions.push('Use merge: git merge --no-ff <branch>'); suggestions.push('Or rebase: git rebase <branch>'); suggestions.push('Or force push: git push --force-with-lease'); } else if (gitError.includes('untracked files')) { code = 'UNTRACKED_FILES'; message = 'Untracked files would be overwritten'; suggestions.push('Add untracked files: git add <files>'); suggestions.push('Or remove untracked files: git clean -fd'); suggestions.push('Or stash untracked files: git stash -u'); } return this.createToolError(code, message, operation, { gitError, projectPath }, suggestions); } /** * Handles provider API errors */ public static handleProviderError( provider: 'github' | 'gitea', apiError: any, operation: string ): ToolResult { let code = 'PROVIDER_ERROR'; let message = `${provider} API error`; const suggestions: string[] = []; // Handle common API errors if (apiError.status === 401) { code = 'AUTHENTICATION_ERROR'; message = `Authentication failed for ${provider}`; suggestions.push(`Check your ${provider.toUpperCase()}_TOKEN environment variable`); suggestions.push('Ensure the token has the required permissions'); suggestions.push('Verify the token is not expired'); } else if (apiError.status === 403) { code = 'PERMISSION_ERROR'; message = `Permission denied for ${provider} operation`; suggestions.push('Check if you have the required permissions for this operation'); suggestions.push('Verify the repository exists and you have access to it'); } else if (apiError.status === 404) { code = 'NOT_FOUND'; message = `Resource not found on ${provider}`; suggestions.push('Check if the repository, issue, or pull request exists'); suggestions.push('Verify the repository name and owner are correct'); } else if (apiError.status === 422) { code = 'VALIDATION_ERROR'; message = `${provider} validation error`; suggestions.push('Check the request parameters'); suggestions.push('Ensure all required fields are provided'); } else if (apiError.status >= 500) { code = 'SERVER_ERROR'; message = `${provider} server error`; suggestions.push('This is a temporary server issue, try again later'); suggestions.push('Check the provider status page for known issues'); } return this.createToolError( code, message, operation, { provider, apiError: apiError.message || apiError }, suggestions ); } /** * Handles network and connectivity errors */ public static handleNetworkError( networkError: any, operation: string, provider?: string ): ToolResult { let code = 'NETWORK_ERROR'; let message = 'Network connectivity error'; const suggestions: string[] = []; if (networkError.code === 'ENOTFOUND') { code = 'DNS_ERROR'; message = 'DNS resolution failed'; suggestions.push('Check your internet connection'); suggestions.push('Verify the server URL is correct'); } else if (networkError.code === 'ECONNREFUSED') { code = 'CONNECTION_REFUSED'; message = 'Connection refused by server'; suggestions.push('Check if the server is running'); suggestions.push('Verify the port and URL are correct'); } else if (networkError.code === 'ETIMEDOUT') { code = 'TIMEOUT_ERROR'; message = 'Request timed out'; suggestions.push('Check your internet connection'); suggestions.push('Try again later - the server may be overloaded'); } return this.createToolError( code, message, operation, { networkError: networkError.message || networkError, provider }, suggestions ); } /** * Handles file system errors */ public static handleFileSystemError( fsError: any, operation: string, filePath?: string ): ToolResult { let code = 'FILESYSTEM_ERROR'; let message = 'File system operation failed'; const suggestions: string[] = []; if (fsError.code === 'ENOENT') { code = 'FILE_NOT_FOUND'; message = 'File or directory not found'; suggestions.push('Check if the file path is correct'); suggestions.push('Ensure the file or directory exists'); } else if (fsError.code === 'EACCES') { code = 'PERMISSION_DENIED'; message = 'Permission denied for file operation'; suggestions.push('Check file permissions'); suggestions.push('Run with appropriate user permissions'); } else if (fsError.code === 'EEXIST') { code = 'FILE_EXISTS'; message = 'File or directory already exists'; suggestions.push('Use a different name or remove the existing file'); suggestions.push('Use update operation instead of create'); } return this.createToolError( code, message, operation, { fsError: fsError.message || fsError, filePath }, suggestions ); } /** * Gets required environment variables for a provider */ private static getRequiredEnvVars(provider?: 'github' | 'gitea' | 'both'): string[] { const envVars: string[] = []; if (provider === 'github' || provider === 'both') { envVars.push('GITHUB_TOKEN', 'GITHUB_USERNAME'); } if (provider === 'gitea' || provider === 'both') { envVars.push('GITEA_URL', 'GITEA_TOKEN', 'GITEA_USERNAME'); } if (!provider) { envVars.push('GITHUB_TOKEN', 'GITHUB_USERNAME', 'GITEA_URL', 'GITEA_TOKEN', 'GITEA_USERNAME'); } return envVars; } /** * Gets example configuration for a provider */ private static getExampleConfig(provider?: 'github' | 'gitea' | 'both'): Record<string, string> { const config: Record<string, string> = {}; if (provider === 'github' || provider === 'both' || !provider) { config.GITHUB_TOKEN = 'ghp_xxxxxxxxxxxxxxxxxxxx'; config.GITHUB_USERNAME = 'your-github-username'; } if (provider === 'gitea' || provider === 'both' || !provider) { config.GITEA_URL = 'https://gitea.example.com'; config.GITEA_TOKEN = 'your-gitea-token'; config.GITEA_USERNAME = 'your-gitea-username'; } return config; } /** * Gets setup instructions for a provider */ private static getSetupInstructions(provider?: 'github' | 'gitea' | 'both'): string[] { const instructions: string[] = []; if (provider === 'github' || provider === 'both' || !provider) { instructions.push('1. For GitHub: Create a personal access token at https://github.com/settings/tokens'); instructions.push('2. Set GITHUB_TOKEN and GITHUB_USERNAME environment variables'); } if (provider === 'gitea' || provider === 'both' || !provider) { instructions.push('3. For Gitea: Create an access token in your Gitea instance settings'); instructions.push('4. Set GITEA_URL, GITEA_TOKEN, and GITEA_USERNAME environment variables'); } instructions.push('5. Restart the MCP server after setting environment variables'); instructions.push('6. At least one provider must be configured for remote operations'); return instructions; } }

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/Andre-Buzeli/git-mcp'

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