Skip to main content
Glama

hypertool-mcp

errors.test.tsโ€ข7.91 kB
/** * Tests for error handling system */ import { describe, test, expect } from "vitest"; import { MetaMCPError, ConnectionError, ServerUnavailableError, ToolError, ToolNotFoundError, ValidationError, RoutingError, TimeoutError, ConfigurationError, isRetryableError, getErrorCode, getUserFriendlyMessage, ERROR_CODES, } from "./index.js"; describe("MetaMCPError", () => { test("should create base error with all properties", () => { const error = new ConnectionError( "Test connection error", "test-server", true, { extra: "context" } ); expect(error.message).toBe("Test connection error"); expect(error.code).toBe("CONNECTION_ERROR"); expect(error.category).toBe("connection"); expect(error.isRetryable).toBe(true); expect(error.serverName).toBe("test-server"); expect(error.context).toEqual({ extra: "context", serverName: "test-server", }); expect(error.timestamp).toBeInstanceOf(Date); }); test("should generate proper stack trace", () => { const error = new ConnectionError("Test error"); expect(error.stack).toBeDefined(); expect(error.stack).toContain("ConnectionError"); }); test("should serialize to JSON properly", () => { const error = new ConnectionError("Test error", "test-server", true, { extra: "data", }); const json = error.toJSON(); expect(json).toMatchObject({ name: "ConnectionError", message: "Test error", code: "CONNECTION_ERROR", category: "connection", isRetryable: true, context: { extra: "data", serverName: "test-server" }, }); expect(json.timestamp).toBeDefined(); expect(json.stack).toBeDefined(); }); }); describe("Specific Error Types", () => { test("ConnectionError should have correct properties", () => { const error = new ConnectionError("Connection failed", "server1", false); expect(error.code).toBe(ERROR_CODES.CONNECTION_ERROR); expect(error.category).toBe("connection"); expect(error.serverName).toBe("server1"); expect(error.isRetryable).toBe(false); expect(error.getUserMessage()).toBe( "Cannot connect to server 'server1': Connection failed" ); }); test("ServerUnavailableError should format message correctly", () => { const error = new ServerUnavailableError("test-server", "maintenance"); expect(error.code).toBe(ERROR_CODES.SERVER_UNAVAILABLE); expect(error.serverName).toBe("test-server"); expect(error.isRetryable).toBe(true); expect(error.getUserMessage()).toBe( "Server 'test-server' is currently unavailable. Please try again later." ); }); test("ToolNotFoundError should provide helpful message", () => { const error = new ToolNotFoundError("missing-tool"); expect(error.code).toBe(ERROR_CODES.TOOL_NOT_FOUND); expect(error.toolName).toBe("missing-tool"); expect(error.isRetryable).toBe(false); expect(error.getUserMessage()).toBe( "Tool 'missing-tool' is not available. Check your configuration or try a different tool." ); }); test("ValidationError should include field information", () => { const error = new ValidationError("Value is required", "username", null); expect(error.code).toBe(ERROR_CODES.VALIDATION_ERROR); expect(error.field).toBe("username"); expect(error.value).toBe(null); expect(error.isRetryable).toBe(false); expect(error.getUserMessage()).toBe("Invalid username: Value is required"); }); test("TimeoutError should include operation details", () => { const error = new TimeoutError("database-query", 5000); expect(error.code).toBe(ERROR_CODES.TIMEOUT_ERROR); expect(error.operation).toBe("database-query"); expect(error.timeoutMs).toBe(5000); expect(error.isRetryable).toBe(true); expect(error.getUserMessage()).toBe( "Operation timed out. Please try again." ); }); test("ConfigurationError should not be retryable", () => { const error = new ConfigurationError("Invalid config format"); expect(error.code).toBe(ERROR_CODES.CONFIG_ERROR); expect(error.isRetryable).toBe(false); expect(error.getUserMessage()).toBe( "Configuration issue: Invalid config format" ); }); }); describe("Error Utilities", () => { test("isRetryableError should identify retryable errors", () => { const retryableError = new ConnectionError( "Connection failed", "server", true ); const nonRetryableError = new ValidationError("Invalid input"); const regularError = new Error("Regular error"); expect(isRetryableError(retryableError)).toBe(true); expect(isRetryableError(nonRetryableError)).toBe(false); expect(isRetryableError(regularError)).toBe(false); }); test("getErrorCode should extract error codes", () => { const mcpError = new ToolError("Tool failed", "test-tool"); const regularError = new Error("Regular error"); expect(getErrorCode(mcpError)).toBe(ERROR_CODES.TOOL_ERROR); expect(getErrorCode(regularError)).toBe("UNKNOWN_ERROR"); }); test("getUserFriendlyMessage should provide user messages", () => { const mcpError = new ServerUnavailableError("test-server"); const regularError = new Error("Internal system error"); expect(getUserFriendlyMessage(mcpError)).toBe( "Server 'test-server' is currently unavailable. Please try again later." ); expect(getUserFriendlyMessage(regularError)).toBe( "An unexpected error occurred. Please try again." ); }); }); describe("Error Context", () => { test("should preserve context through error chain", () => { const originalContext = { requestId: "123", operation: "tool-call" }; const error = new ToolError( "Execution failed", "test-tool", "test-server", originalContext ); expect(error.context).toMatchObject({ ...originalContext, toolName: "test-tool", serverName: "test-server", }); }); test("should handle undefined context gracefully", () => { const error = new ConnectionError("Connection failed"); expect(error.context).toEqual({ serverName: undefined }); }); }); describe("Error Inheritance", () => { test("should maintain instanceof relationships", () => { const connectionError = new ConnectionError("Test"); expect(connectionError instanceof MetaMCPError).toBe(true); expect(connectionError instanceof ConnectionError).toBe(true); expect(connectionError instanceof Error).toBe(true); }); test("should preserve error name", () => { const errors = [ new ConnectionError("test"), new ServerUnavailableError("server"), new ToolNotFoundError("tool"), new ValidationError("test"), new TimeoutError("op", 1000), ]; errors.forEach((error) => { expect(error.name).toBe(error.constructor.name); }); }); }); describe("Error Messages", () => { test("should provide different messages for getUserMessage vs message", () => { const error = new ConnectionError( "ECONNREFUSED: Connection refused by server at localhost:3000", "test-server" ); expect(error.message).toBe( "ECONNREFUSED: Connection refused by server at localhost:3000" ); expect(error.getUserMessage()).toBe( "Cannot connect to server 'test-server': ECONNREFUSED: Connection refused by server at localhost:3000" ); }); test("should handle special cases in user messages", () => { const toolError = new ToolError( "Tool execution failed", "calculator", "math-server" ); expect(toolError.getUserMessage()).toBe( "Tool 'calculator' error: Tool execution failed" ); const routingError = new RoutingError("No route found", "unknown-tool"); expect(routingError.getUserMessage()).toBe( "Request routing failed: No route found" ); }); });

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/toolprint/hypertool-mcp'

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