Skip to main content
Glama
naoto24kawa

Composer Package README MCP Server

by naoto24kawa
error-handler.ts3.56 kB
import { logger } from './logger.js'; import { PackageReadmeMcpError, PackageNotFoundError, RateLimitError, NetworkError, } from '../types/index.js'; export function handleApiError(error: unknown, context: string): never { if (error instanceof PackageReadmeMcpError) { logger.error(`${context}: ${error.message}`, { code: error.code, details: error.details }); throw error; } if (error instanceof Error) { if (error.message.includes('ENOTFOUND') || error.message.includes('ECONNREFUSED')) { const networkError = new NetworkError(`Connection failed in ${context}`, error); logger.error(networkError.message, { originalError: error.message }); throw networkError; } if (error.message.includes('timeout')) { const networkError = new NetworkError(`Request timeout in ${context}`, error); logger.error(networkError.message, { originalError: error.message }); throw networkError; } logger.error(`Unexpected error in ${context}: ${error.message}`, { stack: error.stack }); throw new PackageReadmeMcpError(`Unexpected error in ${context}`, 'UNEXPECTED_ERROR', undefined, error); } logger.error(`Unknown error in ${context}`, { error }); throw new PackageReadmeMcpError(`Unknown error in ${context}`, 'UNKNOWN_ERROR', undefined, error); } export function handleHttpError(status: number, response: Response, context: string): never { const statusText = response.statusText || 'Unknown error'; switch (status) { case 404: throw new PackageNotFoundError(context); case 429: const retryAfter = response.headers.get('retry-after'); const retryAfterSeconds = retryAfter ? parseInt(retryAfter, 10) : undefined; throw new RateLimitError(context, retryAfterSeconds); case 500: case 502: case 503: case 504: throw new NetworkError(`Server error (${status}): ${statusText}`); default: throw new PackageReadmeMcpError( `HTTP error ${status}: ${statusText}`, 'HTTP_ERROR', status ); } } export async function withRetry<T>( fn: () => Promise<T>, maxRetries: number = 3, baseDelay: number = 1000, context: string = 'operation' ): Promise<T> { let lastError: Error; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); if (attempt === maxRetries) { logger.error(`${context} failed after ${maxRetries + 1} attempts`, { error: lastError.message }); break; } if (error instanceof RateLimitError) { const retryAfter = (error.details as { retryAfter?: number })?.retryAfter; const delay = retryAfter ? retryAfter * 1000 : baseDelay * Math.pow(2, attempt); logger.warn(`${context} rate limited, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries + 1})`); await sleep(delay); continue; } if (error instanceof NetworkError || (error instanceof PackageReadmeMcpError && error.statusCode && error.statusCode >= 500)) { const delay = baseDelay * Math.pow(2, attempt); logger.warn(`${context} failed, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries + 1})`, { error: lastError.message }); await sleep(delay); continue; } throw error; } } throw lastError!; } function sleep(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); }

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/naoto24kawa/composer-package-readme-mcp-server'

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