Skip to main content
Glama
errors.ts3.78 kB
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; import { logger } from './logger.js'; // Re-export SDK error types for protocol-level errors export { ErrorCode as McpErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js'; /** * Application-level error codes for tool failures. * * Use these for tool-level errors that should be returned as CallToolResult. * For protocol-level errors (like method not found), use McpError with McpErrorCode. */ export const ToolErrorCodes = { VALIDATION: 'VALIDATION_ERROR', NOT_FOUND: 'NOT_FOUND', UNAUTHORIZED: 'UNAUTHORIZED', FORBIDDEN: 'FORBIDDEN', RATE_LIMIT: 'RATE_LIMIT', TIMEOUT: 'TIMEOUT', INTERNAL: 'INTERNAL_ERROR', EXTERNAL_API: 'EXTERNAL_API_ERROR', CANCELLED: 'CANCELLED', } as const; export type ToolErrorCode = (typeof ToolErrorCodes)[keyof typeof ToolErrorCodes]; /** * Tool error with structured information. * * Throw this in tool handlers for structured error handling. */ export class ToolError extends Error { constructor( message: string, public readonly code: ToolErrorCode, public readonly details?: Record<string, unknown>, ) { super(message); this.name = 'ToolError'; } } /** * Create a standard error result for tool calls. * * @example * return toolError('User not found', 'NOT_FOUND', { userId: 123 }); */ export function toolError( message: string, code: ToolErrorCode = ToolErrorCodes.INTERNAL, details?: Record<string, unknown>, ): CallToolResult { logger.error('tool', { message, code, ...details }); const errorInfo = details ? `\n\nDetails: ${JSON.stringify(details, null, 2)}` : ''; return { isError: true, content: [ { type: 'text', text: `Error [${code}]: ${message}${errorInfo}`, }, ], }; } /** * Create a validation error result from Zod issues. * * @example * const parsed = schema.safeParse(input); * if (!parsed.success) { * return validationError(parsed.error.issues); * } */ export function validationError( issues: Array<{ path: Array<string | number>; message: string }>, ): CallToolResult { const formatted = issues .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`) .join('\n'); return toolError(`Invalid input:\n${formatted}`, ToolErrorCodes.VALIDATION, { issues: issues.map((i) => ({ path: i.path.join('.'), message: i.message })), }); } /** * Create a cancellation error result. */ export function cancelledError(message = 'Operation cancelled'): CallToolResult { return { isError: true, content: [{ type: 'text', text: message }], }; } /** * Wrap an async function with error handling for tools. * Catches exceptions and converts them to proper error results. * * @example * handler: wrapHandler(async (args) => { * // your logic here * return { content: [...] }; * }) */ export function wrapHandler<T>( fn: (args: T) => Promise<CallToolResult>, ): (args: T) => Promise<CallToolResult> { return async (args: T): Promise<CallToolResult> => { try { return await fn(args); } catch (error) { if (error instanceof ToolError) { return toolError(error.message, error.code, error.details); } const message = error instanceof Error ? error.message : String(error); return toolError(message, ToolErrorCodes.INTERNAL); } }; } /** * Assert a condition, throwing ToolError if false. * * @example * assertTool(user !== null, 'User not found', 'NOT_FOUND'); */ export function assertTool( condition: unknown, message: string, code: ToolErrorCode = ToolErrorCodes.INTERNAL, details?: Record<string, unknown>, ): asserts condition { if (!condition) { throw new ToolError(message, code, details); } }

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/iceener/files-stdio-mcp-server'

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