Skip to main content
Glama
mcp-errors.ts6.51 kB
/** * @fileoverview MCP-compliant error handling utilities * * This module provides standardized error handling for Model Context Protocol (MCP) * servers, including error types, formatting, and response generation that comply * with MCP specifications. */ import { ApiResponse } from '../../models/common.js'; /** * Standard MCP error codes based on JSON-RPC 2.0 specification * These codes are exported for use by consumers of the library */ export enum MCPErrorCode { // JSON-RPC 2.0 standard error codes PARSE_ERROR = -32700, INVALID_REQUEST = -32600, METHOD_NOT_FOUND = -32601, INVALID_PARAMS = -32602, INTERNAL_ERROR = -32603, // MCP-specific error codes (range -32000 to -32099) SERVER_ERROR = -32000, RESOURCE_NOT_FOUND = -32001, AUTHENTICATION_ERROR = -32002, AUTHORIZATION_ERROR = -32003, RATE_LIMITED = -32004, TIMEOUT_ERROR = -32005, VALIDATION_ERROR = -32006, DEPENDENCY_ERROR = -32007, CONFIGURATION_ERROR = -32008, // Additional error codes for compatibility NETWORK_ERROR = -32009, CLIENT_ERROR = -32010, } /** * MCP error categories for better error classification * These categories are exported for use by consumers of the library */ export enum MCPErrorCategory { CLIENT_ERROR = 'client_error', SERVER_ERROR = 'server_error', NETWORK_ERROR = 'network_error', VALIDATION_ERROR = 'validation_error', AUTHENTICATION_ERROR = 'authentication_error', RESOURCE_ERROR = 'resource_error', INTERNAL_ERROR = 'internal_error', TRANSPORT_ERROR = 'transport_error', } /** * Interface for structured MCP error information */ export interface MCPErrorInfo { code: MCPErrorCode | string; message: string; category: MCPErrorCategory | string; details?: Record<string, unknown>; cause?: Error; retryable?: boolean; userFriendly?: boolean; } /** * Enhanced error class for MCP-compliant errors */ export class MCPError extends Error { public override readonly name = 'MCPError'; public readonly code: MCPErrorCode | string; public readonly category: MCPErrorCategory | string; public readonly details?: Record<string, unknown>; public override readonly cause?: Error; public readonly retryable: boolean; public readonly userFriendly: boolean; public readonly timestamp: Date; constructor(info: MCPErrorInfo) { super(info.message); this.code = info.code; this.category = info.category; if (info.details !== undefined) { this.details = info.details; } if (info.cause !== undefined) { this.cause = info.cause; } this.retryable = info.retryable ?? false; this.userFriendly = info.userFriendly ?? true; this.timestamp = new Date(); // Maintain proper stack trace if (Error.captureStackTrace) { Error.captureStackTrace(this, MCPError); } } /** * Converts the error to a JSON-serializable object */ toJSON(): Record<string, unknown> { return { name: this.name, message: this.message, code: this.code, category: this.category, details: this.details, retryable: this.retryable, userFriendly: this.userFriendly, timestamp: this.timestamp.toISOString(), stack: this.stack, }; } } // Re-export factory functions export { MCPErrorFactory } from './mcp-error-factory.js'; // Re-export converter functions export { MCPErrorConverter } from './mcp-error-converter.js'; // Re-export formatter functions export { MCPErrorFormatter } from './mcp-error-formatter.js'; /** * Type guard to check if an error is an MCPError */ export function isMCPError(error: unknown): error is MCPError { return error instanceof MCPError; } /** * Validates that a value is not null or undefined */ export function validateRequired<T>(value: T | null | undefined, fieldName: string): T { if (value === null || value === undefined) { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} is required`, retryable: false, userFriendly: true, }); } return value; } /** * Validates that a string is not empty */ export function validateNonEmptyString(value: unknown, fieldName: string): string { const validated = validateRequired(value, fieldName); if (typeof validated !== 'string') { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} must be a non-empty string`, retryable: false, userFriendly: true, }); } if (!validated.trim()) { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} must be a non-empty string`, retryable: false, userFriendly: true, }); } return validated.trim(); } /** * Validates that a number is within a specified range */ export function validateNumberRange( value: number, fieldName: string, min?: number, max?: number ): number { if (typeof value !== 'number' || isNaN(value)) { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} must be a valid number`, retryable: false, userFriendly: true, }); } if (min !== undefined && value < min) { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} must be >= ${min}`, retryable: false, userFriendly: true, }); } if (max !== undefined && value > max) { throw new MCPError({ code: MCPErrorCode.VALIDATION_ERROR, category: MCPErrorCategory.VALIDATION_ERROR, message: `Validation failed: ${fieldName} must be <= ${max}`, retryable: false, userFriendly: true, }); } return value; } /** * Higher-order function to wrap handlers with MCP-compliant error handling */ export function withMCPErrorHandling<TParams, TResult>( handler: (_params: TParams) => Promise<TResult>, context?: string ) { return async (params: TParams): Promise<TResult | ApiResponse> => { try { return await handler(params); } catch (error) { const { createErrorResponse } = await import('./mcp-error-formatter.js'); return createErrorResponse(error, context); } }; }

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/sapientpants/deepsource-mcp-server'

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