133 lines
2.7 KiB
TypeScript
133 lines
2.7 KiB
TypeScript
import { Logger } from './logger.util.js';
|
|
|
|
/**
|
|
* Error types for classification
|
|
*/
|
|
export enum ErrorType {
|
|
AUTH_MISSING = 'AUTH_MISSING',
|
|
AUTH_INVALID = 'AUTH_INVALID',
|
|
API_ERROR = 'API_ERROR',
|
|
UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
|
|
}
|
|
|
|
/**
|
|
* Custom error class with type classification
|
|
*/
|
|
export class McpError extends Error {
|
|
type: ErrorType;
|
|
statusCode?: number;
|
|
originalError?: unknown;
|
|
|
|
constructor(
|
|
message: string,
|
|
type: ErrorType,
|
|
statusCode?: number,
|
|
originalError?: unknown,
|
|
) {
|
|
super(message);
|
|
this.name = 'McpError';
|
|
this.type = type;
|
|
this.statusCode = statusCode;
|
|
this.originalError = originalError;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create an unexpected error
|
|
*/
|
|
export function createUnexpectedError(
|
|
message: string = 'An unexpected error occurred',
|
|
originalError?: unknown,
|
|
): McpError {
|
|
return new McpError(
|
|
message,
|
|
ErrorType.UNEXPECTED_ERROR,
|
|
undefined,
|
|
originalError,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Ensure an error is an McpError
|
|
*/
|
|
export function ensureMcpError(error: unknown): McpError {
|
|
if (error instanceof McpError) {
|
|
return error;
|
|
}
|
|
|
|
if (error instanceof Error) {
|
|
return createUnexpectedError(error.message, error);
|
|
}
|
|
|
|
return createUnexpectedError(String(error));
|
|
}
|
|
|
|
/**
|
|
* Get the deepest original error from an error chain
|
|
* @param error The error to extract the original cause from
|
|
* @returns The deepest original error or the error itself
|
|
*/
|
|
export function getDeepOriginalError(error: unknown): unknown {
|
|
if (!error) {
|
|
return error;
|
|
}
|
|
|
|
let current = error;
|
|
let depth = 0;
|
|
const maxDepth = 10; // Prevent infinite recursion
|
|
|
|
while (
|
|
depth < maxDepth &&
|
|
current instanceof Error &&
|
|
'originalError' in current &&
|
|
current.originalError
|
|
) {
|
|
current = current.originalError;
|
|
depth++;
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
/**
|
|
* Format error for MCP tool response
|
|
*/
|
|
export function formatErrorForMcpTool(error: unknown): {
|
|
content: Array<{ type: 'text'; text: string }>;
|
|
metadata?: {
|
|
errorType: ErrorType;
|
|
statusCode?: number;
|
|
errorDetails?: unknown;
|
|
};
|
|
} {
|
|
const methodLogger = Logger.forContext(
|
|
'utils/error.util.ts',
|
|
'formatErrorForMcpTool',
|
|
);
|
|
const mcpError = ensureMcpError(error);
|
|
methodLogger.error(`${mcpError.type} error`, mcpError);
|
|
|
|
// Get the deep original error for additional context
|
|
const originalError = getDeepOriginalError(mcpError.originalError);
|
|
|
|
// Safely extract details from the original error
|
|
const errorDetails =
|
|
originalError instanceof Error
|
|
? { message: originalError.message }
|
|
: originalError;
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text' as const,
|
|
text: `Error: ${mcpError.message}`,
|
|
},
|
|
],
|
|
metadata: {
|
|
errorType: mcpError.type,
|
|
statusCode: mcpError.statusCode,
|
|
errorDetails,
|
|
},
|
|
};
|
|
}
|