Skip to main content
Glama
cameronsjo

MCP Server Template

by cameronsjo
errors.ts4.23 kB
/** * Custom error classes for structured error handling * * All errors extend McpServerError and include structured metadata * for consistent error formatting and observability. */ import { ErrorCode, type ErrorResponse } from '../types/index.js'; /** * Base error class for MCP server errors */ export class McpServerError extends Error { readonly code: ErrorCode; readonly details?: Record<string, unknown>; readonly retryable: boolean; readonly retryAfterSeconds?: number; constructor( message: string, code: ErrorCode, options?: { details?: Record<string, unknown>; retryable?: boolean; retryAfterSeconds?: number; cause?: Error; } ) { super(message, { cause: options?.cause }); this.name = 'McpServerError'; this.code = code; this.details = options?.details; this.retryable = options?.retryable ?? false; this.retryAfterSeconds = options?.retryAfterSeconds; } /** * Convert to structured error response */ toResponse(): ErrorResponse { return { error: this.message, code: this.code, details: this.details, retryable: this.retryable, retryAfterSeconds: this.retryAfterSeconds, }; } } /** * Resource not found error */ export class NotFoundError extends McpServerError { constructor(resource: string, identifier?: string) { super( identifier ? `${resource} not found: ${identifier}` : `${resource} not found`, ErrorCode.NOT_FOUND, { details: { resource, identifier }, retryable: false, } ); this.name = 'NotFoundError'; } } /** * Input validation error */ export class ValidationError extends McpServerError { constructor(message: string, details?: Record<string, unknown>) { super(message, ErrorCode.VALIDATION_ERROR, { details, retryable: false, }); this.name = 'ValidationError'; } } /** * Rate limiting error */ export class RateLimitError extends McpServerError { constructor(retryAfterSeconds: number = 60) { super('Rate limit exceeded', ErrorCode.RATE_LIMITED, { retryable: true, retryAfterSeconds, }); this.name = 'RateLimitError'; } } /** * External API error */ export class ExternalApiError extends McpServerError { constructor(service: string, message: string, cause?: Error) { super(`${service}: ${message}`, ErrorCode.EXTERNAL_API_ERROR, { details: { service }, retryable: true, cause, }); this.name = 'ExternalApiError'; } } /** * Timeout error */ export class TimeoutError extends McpServerError { constructor(operation: string, timeoutMs: number) { super(`${operation} timed out after ${timeoutMs}ms`, ErrorCode.TIMEOUT, { details: { operation, timeoutMs }, retryable: true, }); this.name = 'TimeoutError'; } } /** * Cache error */ export class CacheError extends McpServerError { constructor(message: string, cause?: Error) { super(message, ErrorCode.CACHE_ERROR, { retryable: false, cause, }); this.name = 'CacheError'; } } /** * Authentication error */ export class AuthenticationError extends McpServerError { constructor(message: string, details?: Record<string, unknown>) { super(message, ErrorCode.UNAUTHORIZED, { details, retryable: false, }); this.name = 'AuthenticationError'; } } /** * Authorization error (authenticated but insufficient permissions) */ export class AuthorizationError extends McpServerError { constructor(message: string, requiredScopes?: string[]) { super(message, ErrorCode.FORBIDDEN, { details: requiredScopes ? { requiredScopes } : undefined, retryable: false, }); this.name = 'AuthorizationError'; } } /** * Format any error into a structured response */ export function formatErrorResponse(error: unknown): ErrorResponse { if (error instanceof McpServerError) { return error.toResponse(); } if (error instanceof Error) { return { error: error.message, code: ErrorCode.INTERNAL_ERROR, retryable: false, }; } return { error: String(error), code: ErrorCode.INTERNAL_ERROR, retryable: false, }; }

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/cameronsjo/mcp-server-template'

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