Skip to main content
Glama
by wei
error-handlers.ts5.35 kB
/** * Error Handling Utilities * * Provides functions to map various error types to MCP-compatible responses. * All error messages follow the patterns defined in tool-contracts.md. */ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import type { ZodError } from "zod"; /** * Error types for categorization */ export type ErrorType = "validation" | "api" | "network" | "not_found" | "rate_limit" | "unknown"; /** * Structured error response */ export interface ErrorResponse { type: ErrorType; message: string; details?: unknown; statusCode?: number; } /** * Create an MCP tool error result * * @param error - Error response object * @returns MCP-compatible tool result with error flag */ export function createErrorResult(error: ErrorResponse): CallToolResult { return { content: [ { type: "text", text: JSON.stringify(error, null, 2), }, ], isError: true, }; } /** * Map Zod validation errors to MCP error result * * @param error - ZodError from validation failure * @returns MCP tool result with validation error details * * @example * ```typescript * try { * validateInput(schema, input); * } catch (error) { * if (error instanceof ZodError) { * return handleValidationError(error); * } * } * ``` */ export function handleValidationError(error: ZodError): CallToolResult { const firstError = error.errors[0]; const fieldPath = firstError?.path.join(".") || "input"; const message = firstError?.message || "Validation failed"; return createErrorResult({ type: "validation", message: `Validation error: ${fieldPath} - ${message}`, details: error.errors.map((err) => ({ field: err.path.join("."), message: err.message, received: err.code, })), statusCode: 400, }); } /** * Map API errors to MCP error result * * @param error - Error from API request * @param context - Additional context about the operation * @returns MCP tool result with API error details * * @example * ```typescript * try { * await hnApi.getItem(itemId); * } catch (error) { * return handleAPIError(error, "fetching item"); * } * ``` */ export function handleAPIError(error: unknown, context = "API request"): CallToolResult { if (!(error instanceof Error)) { return createErrorResult({ type: "unknown", message: `Unknown error during ${context}`, details: String(error), statusCode: 500, }); } return handleErrorInstance(error, context); } /** * Handle Error instance and convert to CallToolResult * Extracted to reduce complexity of handleAPIError */ function handleErrorInstance(error: Error, context: string): CallToolResult { // Check for timeout errors if (error.message.includes("timeout")) { return createErrorResult({ type: "network", message: `Request timeout: ${context} took too long to complete`, details: error.message, statusCode: 504, }); } // Check for rate limit (HTTP 429) if (error.message.includes("429")) { return createErrorResult({ type: "rate_limit", message: "Rate limit exceeded: 10,000 requests per hour maximum. Please try again later.", details: error.message, statusCode: 429, }); } // Check for not found (HTTP 404) if (error.message.includes("404")) { return createErrorResult({ type: "not_found", message: `Not found: The requested resource could not be found during ${context}`, details: error.message, statusCode: 404, }); } // Check for HTTP errors if (error.message.includes("HTTP")) { return handleHTTPError(error, context); } // Generic API error return createErrorResult({ type: "api", message: `API error: Failed during ${context} - ${error.message}`, details: error.message, statusCode: 500, }); } /** * Handle HTTP errors and extract status code */ function handleHTTPError(error: Error, context: string): CallToolResult { const statusMatch = error.message.match(/HTTP (\d+)/); const statusCode = statusMatch?.[1] ? Number.parseInt(statusMatch[1], 10) : 500; return createErrorResult({ type: "api", message: `API error: Failed during ${context} - ${error.message}`, details: error.message, statusCode, }); } /** * Create a success tool result * * @param data - Result data to return * @returns MCP-compatible tool result with structured content * * @example * ```typescript * const results = await hnApi.search(params); * return createSuccessResult(results); * ``` */ export function createSuccessResult(data: unknown): CallToolResult { return { content: [ { type: "text", text: JSON.stringify(data, null, 2), }, ], structuredContent: data as Record<string, unknown>, isError: false, }; } /** * Check if an item exists in API response * * @param data - API response data * @param itemType - Type of item (for error message) * @param identifier - Item identifier (for error message) * @returns Error result if item doesn't exist, null otherwise */ export function checkItemExists( data: unknown, itemType: string, identifier: string ): CallToolResult | null { if (!data || (typeof data === "object" && Object.keys(data).length === 0)) { return createErrorResult({ type: "not_found", message: `${itemType} not found: No ${itemType.toLowerCase()} with identifier '${identifier}'`, statusCode: 404, }); } return null; }

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/wei/hn-mcp-server'

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