Skip to main content
Glama
errorHandler.ts4.51 kB
import logger from './logger.js'; /** * Extracts a helpful error message from an Axios error or generic error * This provides much more context than just "Request failed with status code XXX" */ export function formatApiError(error: any, context: string = 'API request'): string { // Log the full error for debugging logger.error(`Error in ${context}: ${error.message}`); if (error.stack) { logger.error(`Stack trace: ${error.stack}`); } // Check if this is an Axios error with a response if (error.response) { const { status, statusText, data } = error.response; logger.error(`API response error: ${JSON.stringify({ status, statusText, data })}`); // Build a helpful error message let message = `${context} failed (HTTP ${status}`; if (statusText) { message += ` ${statusText}`; } message += ')'; // Extract useful information from the response data if (data) { // Teamwork API often returns error messages in these formats if (typeof data === 'string') { message += `: ${data}`; } else if (typeof data === 'object') { // Helper to extract message from error objects const extractErrorMessages = (errors: any[]): string | null => { if (!Array.isArray(errors) || errors.length === 0) return null; return errors.map(e => { if (typeof e === 'string') return e; if (typeof e === 'object' && e !== null) { return e.message || e.detail || e.error || JSON.stringify(e); } return String(e); }).join(', '); }; // Check common error message fields used by Teamwork API let errorMessage: string | null = null; if (data.message) { errorMessage = data.message; } else if (data.error) { errorMessage = typeof data.error === 'string' ? data.error : JSON.stringify(data.error); } else if (data.MESSAGE) { errorMessage = data.MESSAGE; } else if (data.errors) { errorMessage = extractErrorMessages(data.errors); } else if (data.details) { errorMessage = typeof data.details === 'string' ? data.details : JSON.stringify(data.details); } else if (Array.isArray(data) && data.length > 0) { errorMessage = extractErrorMessages(data); } if (errorMessage) { message += `: ${errorMessage}`; } else { // If no standard error field, stringify the data (truncated) const dataStr = JSON.stringify(data); if (dataStr.length > 200) { message += `: ${dataStr.substring(0, 200)}...`; } else if (dataStr !== '{}') { message += `: ${dataStr}`; } } } } // Add hints for common status codes switch (status) { case 400: message += '\n\nHint: Check that all required parameters are provided and have valid values.'; break; case 401: message += '\n\nHint: Authentication failed. Check your TEAMWORK_USERNAME and TEAMWORK_PASSWORD credentials.'; break; case 403: message += '\n\nHint: You do not have permission to perform this action.'; break; case 404: message += '\n\nHint: The requested resource was not found. Check that the ID exists.'; break; case 422: message += '\n\nHint: The request data was invalid. Check the field values.'; break; case 429: message += '\n\nHint: Rate limit exceeded. Please wait before making more requests.'; break; case 500: case 502: case 503: message += '\n\nHint: Teamwork server error. Please try again later.'; break; } return message; } // Check if this is an Axios error without a response (network error) if (error.request) { logger.error(`Network error (no response received): ${error.message}`); return `${context} failed: No response received from server. Please check your network connection and TEAMWORK_DOMAIN setting.`; } // Generic error return `${context} failed: ${error.message}`; } /** * Creates a standard MCP error response object */ export function createErrorResponse(error: any, context: string = 'API request') { return { content: [{ type: "text", text: formatApiError(error, context) }] }; } export default { formatApiError, createErrorResponse };

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/Vizioz/Teamwork-MCP'

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