@takashito/linode-mcp-server
Version:
MCP server for Linode API
121 lines • 4.84 kB
JavaScript
;
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 = '';
// 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, context) => {
try {
return await handler(params, context);
}
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