/**
* Standardized error handling for MCP tools
*/
import type { ErrorCode, QuantError } from "@quant-companion/core";
/**
* Create a standardized error response
*/
export function createError(
code: ErrorCode,
message: string,
details?: Record<string, unknown>
): QuantError {
return { code, message, details };
}
/**
* Wrap a tool handler with standardized error handling
*/
export function wrapToolHandler<T, R>(
handler: (input: T) => R | Promise<R>
): (input: T) => Promise<{ result?: R; error?: QuantError }> {
return async (input: T) => {
try {
const result = await handler(input);
return { result };
} catch (err) {
const message = err instanceof Error ? err.message : "Unknown error";
// Categorize error by name first, then message patterns
let code: ErrorCode = "COMPUTATION_ERROR";
const errName = err instanceof Error ? err.name : "";
// Check error name first (explicit categorization)
if (errName === "LIMIT_EXCEEDED") {
code = "LIMIT_EXCEEDED";
} else if (errName === "INVALID_INPUT") {
code = "INVALID_INPUT";
}
// Fall back to message pattern matching
else if (message.includes("not found") || message.includes("No data")) {
code = "DATA_NOT_FOUND";
} else if (message.includes("Limit exceeded") || message.includes("limit exceeded")) {
code = "LIMIT_EXCEEDED";
} else if (message.includes("must be") || message.includes("cannot") || message.includes("Invalid")) {
code = "INVALID_INPUT";
} else if (message.includes("converge") || message.includes("Convergence")) {
code = "CONVERGENCE_FAILED";
}
return {
error: createError(code, message, {
input,
stack: err instanceof Error ? err.stack : undefined,
}),
};
}
};
}
/**
* Tool execution limits
*/
export const LIMITS = {
/** Maximum simulation paths */
MAX_PATHS: 200_000,
/** Default simulation paths */
DEFAULT_PATHS: 50_000,
/** Maximum historical data days */
MAX_HISTORICAL_DAYS: 365 * 10, // 10 years
/** Maximum payoffs to return in response */
MAX_PAYOFFS_RETURNED: 10_000,
} as const;