UNPKG

@takashito/linode-mcp-server

Version:

MCP server for Linode API

133 lines 5.68 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.formatLinodeError = formatLinodeError; exports.withErrorHandling = withErrorHandling; exports.registerToolsWithErrorHandling = registerToolsWithErrorHandling; const axios_1 = __importDefault(require("axios")); /** * Formats an error message from a Linode API error response * * @param error The error from the Linode API * @returns A formatted error message */ function formatLinodeError(error) { // Default error message let errorMessage = 'An error occurred while processing your request.'; if (axios_1.default.isAxiosError(error)) { const axiosError = error; // Include status code and method/URL info const statusCode = axiosError.response?.status; const method = axiosError.config?.method?.toUpperCase() || 'REQUEST'; const url = axiosError.config?.url || 'unknown endpoint'; errorMessage = `API Error ${statusCode} [${method} ${url}]: `; // Format response data if (axiosError.response?.data?.errors && axiosError.response.data.errors.length > 0) { const errors = axiosError.response.data.errors; // Group errors by field const errorsByField = {}; errors.forEach(err => { const field = err.field || 'general'; if (!errorsByField[field]) { errorsByField[field] = []; } errorsByField[field].push(err.reason); }); // Format the error message with details const formattedErrors = Object.entries(errorsByField).map(([field, reasons]) => { if (field === 'general') { return reasons.join('; '); } return `${field}: ${reasons.join('; ')}`; }); // Add troubleshooting hints based on common errors let hints = ''; // Password related errors if (errorsByField['root_pass'] && errorsByField['root_pass'].some(msg => msg.includes('strength requirement'))) { hints += '\nHint: Passwords must include uppercase, lowercase, numbers, and special characters.'; } // Image related errors if (errorsByField['image'] && errorsByField['image'].some(msg => msg.includes('not found'))) { hints += '\nHint: Available images include: linode/debian11, linode/ubuntu22.04, linode/centos7, etc.'; } // Type related errors if (errorsByField['type'] && errorsByField['type'].some(msg => msg.includes('not found'))) { hints += '\nHint: Valid Linode types include: g6-nanode-1, g6-standard-1, g6-standard-2, etc.'; } // Rate limiting if (statusCode === 429) { hints += '\nHint: You have exceeded the API rate limit. Please wait before making more requests.'; } // Authentication errors if (statusCode === 401) { hints += '\nHint: Check that your API token is valid and has the necessary permissions.'; } errorMessage += formattedErrors.join(' | ') + hints; } else if (axiosError.response?.data) { // Try to include as much of the response data as possible try { errorMessage += JSON.stringify(axiosError.response.data); } catch (e) { errorMessage += axiosError.response.statusText || axiosError.message; } } else if (axiosError.response?.statusText) { // Use status text as fallback errorMessage += axiosError.response.statusText; } else if (axiosError.message) { // Use error message as fallback errorMessage += axiosError.message; } // Network errors if (axiosError.code === 'ECONNREFUSED') { errorMessage = 'Could not connect to the Linode API. Please check your internet connection.'; } else if (axiosError.code === 'ENOTFOUND') { errorMessage = 'Could not resolve the Linode API domain. Please check your internet connection or DNS settings.'; } } else if (error instanceof Error) { // Handle regular errors errorMessage = `Error: ${error.message}`; // Include stack trace for detailed debugging in non-production environments if (process.env.NODE_ENV !== 'production') { errorMessage += `\nStack trace: ${error.stack}`; } } return errorMessage; } /** * Wraps a tool handler with error handling * * @param handler The handler function to wrap * @returns A wrapped handler function with error handling */ function withErrorHandling(handler) { return async (params, extra) => { try { return await handler(params, extra); } catch (error) { const errorMessage = formatLinodeError(error); // Throw an error with the formatted message throw new Error(errorMessage); } }; } /** * Registers all tools with error handling * * @param server The MCP server * @param tools Array of tool registrations */ function registerToolsWithErrorHandling(server, tools) { tools.forEach(tool => { server.tool(tool.name, tool.description, tool.schema, withErrorHandling(tool.handler)); }); } //# sourceMappingURL=errorHandler.js.map