@toolprint/hypertool-mcp
Version:
HyperTool MCP proxy server for routing requests between clients and multiple underlying MCP servers
282 lines • 12.3 kB
JavaScript
/**
* User-friendly error messages and message templates
*/
import { MetaMCPError, ERROR_CODES } from "./index.js";
/**
* Common error scenarios and their user-friendly messages
*/
export const ERROR_MESSAGES = {
// Configuration errors
INVALID_CONFIG: "Configuration file is invalid or corrupted. Please check your .mcp.json file.",
MISSING_CONFIG: "Configuration file not found. Please create a .mcp.json file with your server configurations.",
INVALID_SERVER_CONFIG: "Server configuration is invalid. Please check the server settings in your configuration file.",
// Connection errors
SERVER_NOT_FOUND: "The specified server could not be found. Please check that the server name is correct.",
CONNECTION_REFUSED: "Unable to connect to the server. Please ensure the server is running and accessible.",
CONNECTION_TIMEOUT: "Connection attempt timed out. The server may be overloaded or unreachable.",
CONNECTION_LOST: "Connection to the server was lost. The system will attempt to reconnect automatically.",
// Server availability
SERVER_UNAVAILABLE: "The server is temporarily unavailable. Please try again in a few moments.",
SERVER_MAINTENANCE: "The server is currently undergoing maintenance. Please try again later.",
SERVER_OVERLOADED: "The server is currently overloaded. Please try again in a few moments.",
// Tool errors
TOOL_NOT_FOUND: "The requested tool is not available. Please check the tool name or your configuration.",
TOOL_DISABLED: "This tool has been disabled. Please contact your administrator for assistance.",
TOOL_EXECUTION_FAILED: "The tool failed to execute. Please check your parameters and try again.",
INVALID_TOOL_PARAMS: "Invalid parameters provided to the tool. Please check the tool documentation.",
// Authentication and authorization
UNAUTHORIZED: "You are not authorized to perform this action. Please check your permissions.",
AUTHENTICATION_FAILED: "Authentication failed. Please check your credentials.",
TOKEN_EXPIRED: "Your session has expired. Please log in again.",
// Rate limiting
RATE_LIMITED: "Too many requests. Please wait a moment before trying again.",
QUOTA_EXCEEDED: "You have exceeded your usage quota. Please contact your administrator.",
// System errors
INTERNAL_ERROR: "An internal error occurred. Our team has been notified and is working to resolve the issue.",
SERVICE_DEGRADED: "The service is experiencing degraded performance. Some features may be unavailable.",
MAINTENANCE_MODE: "The system is currently in maintenance mode. Please try again later.",
// Network errors
NETWORK_ERROR: "A network error occurred. Please check your internet connection and try again.",
DNS_ERROR: "Unable to resolve server address. Please check your network configuration.",
SSL_ERROR: "SSL/TLS connection error. Please check your security settings.",
// Validation errors
MISSING_REQUIRED_FIELD: "A required field is missing. Please provide all necessary information.",
INVALID_FORMAT: "The provided data is in an invalid format. Please check and correct your input.",
VALUE_OUT_OF_RANGE: "The provided value is outside the acceptable range.",
// General fallback
UNKNOWN_ERROR: "An unexpected error occurred. Please try again, and contact support if the problem persists.",
};
/**
* Error message templates with parameter substitution
*/
export const ERROR_TEMPLATES = {
SERVER_UNAVAILABLE_WITH_NAME: "Server '{serverName}' is currently unavailable. Please try again later.",
TOOL_NOT_FOUND_WITH_NAME: "Tool '{toolName}' is not available. Please check your configuration.",
CONNECTION_FAILED_WITH_SERVER: "Failed to connect to server '{serverName}'. Please ensure it is running and accessible.",
TIMEOUT_WITH_OPERATION: "Operation '{operation}' timed out after {timeout}ms. Please try again.",
VALIDATION_FAILED_WITH_FIELD: "Invalid value for field '{field}': {reason}",
TOOL_ERROR_WITH_DETAILS: "Tool '{toolName}' failed: {error}",
SERVER_ERROR_WITH_CODE: "Server error (code: {code}): {message}",
RATE_LIMITED_WITH_RETRY: "Too many requests. Please wait {retryAfter} seconds before trying again.",
QUOTA_EXCEEDED_WITH_LIMIT: "Usage quota exceeded. Limit: {limit}, Current: {current}. Resets at {resetTime}.",
CIRCUIT_BREAKER_OPEN: "Service '{serviceName}' is temporarily unavailable due to repeated failures. Please try again in {recoveryTime} seconds.",
};
/**
* Suggestion messages for common errors
*/
export const ERROR_SUGGESTIONS = {
[ERROR_CODES.CONNECTION_ERROR]: [
"Check that the server is running and accessible",
"Verify your network connection",
"Ensure the server configuration is correct",
"Try again in a few moments",
],
[ERROR_CODES.SERVER_UNAVAILABLE]: [
"Wait a few moments and try again",
"Check if the server is undergoing maintenance",
"Verify the server is properly configured",
"Contact your administrator if the issue persists",
],
[ERROR_CODES.TOOL_NOT_FOUND]: [
"Check the tool name spelling",
"Verify the tool is configured in your .mcp.json file",
"Ensure the underlying server is connected",
"Check if the tool has been renamed or removed",
],
[ERROR_CODES.CONFIG_ERROR]: [
"Review your .mcp.json configuration file",
"Check for syntax errors in the configuration",
"Verify all required fields are present",
"Refer to the configuration documentation",
],
[ERROR_CODES.VALIDATION_ERROR]: [
"Check that all required parameters are provided",
"Verify parameter types and formats",
"Review the tool documentation for parameter requirements",
"Ensure values are within acceptable ranges",
],
[ERROR_CODES.TIMEOUT_ERROR]: [
"Try the operation again",
"Check your network connection speed",
"Consider breaking large operations into smaller parts",
"Contact support if timeouts persist",
],
};
/**
* Error category descriptions for users
*/
export const ERROR_CATEGORY_DESCRIPTIONS = {
configuration: "Issues with server or tool configuration",
connection: "Problems connecting to underlying servers",
availability: "Temporary server or service unavailability",
tool: "Issues with tool execution or availability",
validation: "Invalid parameters or request format",
routing: "Problems routing requests to the correct server",
health: "Server health monitoring issues",
timeout: "Operations that took too long to complete",
discovery: "Issues discovering available tools",
};
/**
* Utility class for generating user-friendly error messages
*/
export class ErrorMessageGenerator {
/**
* Generate a user-friendly message for an error
*/
static getUserMessage(error) {
if (error instanceof MetaMCPError) {
return error.getUserMessage();
}
// Try to map common error patterns to friendly messages
const message = error.message.toLowerCase();
if (message.includes("connection refused") ||
message.includes("econnrefused")) {
return ERROR_MESSAGES.CONNECTION_REFUSED;
}
if (message.includes("timeout") || message.includes("etimedout")) {
return ERROR_MESSAGES.CONNECTION_TIMEOUT;
}
if (message.includes("not found") || message.includes("404")) {
return ERROR_MESSAGES.TOOL_NOT_FOUND;
}
if (message.includes("unauthorized") || message.includes("401")) {
return ERROR_MESSAGES.UNAUTHORIZED;
}
if (message.includes("rate limit") || message.includes("429")) {
return ERROR_MESSAGES.RATE_LIMITED;
}
if (message.includes("network") || message.includes("dns")) {
return ERROR_MESSAGES.NETWORK_ERROR;
}
// Default fallback
return ERROR_MESSAGES.UNKNOWN_ERROR;
}
/**
* Generate message from template with parameter substitution
*/
static fromTemplate(template, params) {
let message = template;
for (const [key, value] of Object.entries(params)) {
const placeholder = `{${key}}`;
message = message.replace(new RegExp(placeholder, "g"), String(value));
}
return message;
}
/**
* Get suggestions for an error
*/
static getSuggestions(error) {
if (error instanceof MetaMCPError) {
const suggestions = ERROR_SUGGESTIONS[error.code];
return suggestions ? [...suggestions] : [];
}
return [];
}
/**
* Generate a comprehensive error response for users
*/
static generateErrorResponse(error, includeDetails = false) {
const userMessage = this.getUserMessage(error);
const suggestions = this.getSuggestions(error);
const response = {
error: true,
message: userMessage,
timestamp: new Date().toISOString(),
};
if (suggestions.length > 0) {
response.suggestions = suggestions;
}
if (error instanceof MetaMCPError) {
response.category = error.category;
response.isRetryable = error.isRetryable;
if (includeDetails) {
response.code = error.code;
response.context = error.context;
}
}
if (includeDetails) {
response.details = {
originalMessage: error.message,
stack: error.stack,
};
}
return response;
}
/**
* Format error for logging (with full details)
*/
static formatForLogging(error, context) {
return {
name: error.name,
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
...(error instanceof MetaMCPError && {
code: error.code,
category: error.category,
isRetryable: error.isRetryable,
errorContext: error.context,
}),
...(context && { context }),
};
}
/**
* Check if error should be shown to user
*/
static shouldShowToUser(error) {
// Don't show internal errors or sensitive information
if (error.message.includes("INTERNAL_") ||
error.message.includes("password") ||
error.message.includes("token") ||
error.message.includes("secret")) {
return false;
}
return true;
}
}
/**
* Common error scenarios with pre-built responses
*/
export const COMMON_ERROR_RESPONSES = {
serverUnavailable: (serverName) => ({
content: [
{
type: "text",
text: ErrorMessageGenerator.fromTemplate(ERROR_TEMPLATES.SERVER_UNAVAILABLE_WITH_NAME, { serverName }),
},
],
isError: true,
suggestions: ERROR_SUGGESTIONS[ERROR_CODES.SERVER_UNAVAILABLE],
}),
toolNotFound: (toolName) => ({
content: [
{
type: "text",
text: ErrorMessageGenerator.fromTemplate(ERROR_TEMPLATES.TOOL_NOT_FOUND_WITH_NAME, { toolName }),
},
],
isError: true,
suggestions: ERROR_SUGGESTIONS[ERROR_CODES.TOOL_NOT_FOUND],
}),
connectionFailed: (serverName, reason) => ({
content: [
{
type: "text",
text: ErrorMessageGenerator.fromTemplate(ERROR_TEMPLATES.CONNECTION_FAILED_WITH_SERVER, { serverName }) + (reason ? ` Reason: ${reason}` : ""),
},
],
isError: true,
suggestions: ERROR_SUGGESTIONS[ERROR_CODES.CONNECTION_ERROR],
}),
validationFailed: (field, reason) => ({
content: [
{
type: "text",
text: ErrorMessageGenerator.fromTemplate(ERROR_TEMPLATES.VALIDATION_FAILED_WITH_FIELD, { field, reason }),
},
],
isError: true,
suggestions: ERROR_SUGGESTIONS[ERROR_CODES.VALIDATION_ERROR],
}),
};
//# sourceMappingURL=messages.js.map