Skip to content

Commit e40c7ed

Browse files
authored
refactor: wrap setRequestHandler for high-level servers (#14)
* refactor: wrap setRequestHandler for high-level servers * catch error in tool execution and put it in extra param
1 parent 98729f8 commit e40c7ed

File tree

6 files changed

+685
-169
lines changed

6 files changed

+685
-169
lines changed

src/modules/exceptions.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,30 @@ const MAX_STACK_FRAMES = 50;
1515
* detects whether each frame is user code (in_app: true) or library code (in_app: false).
1616
*
1717
* @param error - The error to capture (can be Error, string, object, or any value)
18+
* @param contextStack - Optional Error object to use for stack context (for validation errors)
1819
* @returns ErrorData object with structured error information
1920
*/
20-
export function captureException(error: unknown): ErrorData {
21+
export function captureException(
22+
error: unknown,
23+
contextStack?: Error,
24+
): ErrorData {
25+
// Handle CallToolResult objects (SDK 1.21.0+ converts errors to these)
26+
if (isCallToolResult(error)) {
27+
return captureCallToolResultError(error, contextStack);
28+
}
29+
2130
// Handle non-Error objects
2231
if (!(error instanceof Error)) {
2332
return {
2433
message: stringifyNonError(error),
25-
type: "NonError",
34+
type: undefined,
2635
platform: "javascript",
2736
};
2837
}
2938

3039
const errorData: ErrorData = {
3140
message: error.message || "",
32-
type: error.name || error.constructor?.name || "Error",
41+
type: error.name || error.constructor?.name || undefined,
3342
platform: "javascript",
3443
};
3544

@@ -677,7 +686,7 @@ function unwrapErrorCauses(error: Error): ChainedErrorData[] {
677686
if (!(currentError instanceof Error)) {
678687
chainedErrors.push({
679688
message: stringifyNonError(currentError),
680-
type: "NonError",
689+
type: "UnknownErrorType",
681690
});
682691
break;
683692
}
@@ -708,6 +717,57 @@ function unwrapErrorCauses(error: Error): ChainedErrorData[] {
708717
return chainedErrors;
709718
}
710719

720+
/**
721+
* Detects if a value is a CallToolResult object (SDK 1.21.0+ error format).
722+
*
723+
* SDK 1.21.0+ converts errors to CallToolResult format:
724+
* { content: [{ type: "text", text: "error message" }], isError: true }
725+
*
726+
* @param value - Value to check
727+
* @returns True if value is a CallToolResult object
728+
*/
729+
function isCallToolResult(value: unknown): boolean {
730+
return (
731+
value !== null &&
732+
typeof value === "object" &&
733+
"isError" in value &&
734+
"content" in value &&
735+
Array.isArray((value as any).content)
736+
);
737+
}
738+
739+
/**
740+
* Extracts error information from CallToolResult objects.
741+
*
742+
* SDK 1.21.0+ converts errors to CallToolResult, losing original stack traces.
743+
* This extracts the error message from the content array.
744+
*
745+
* @param result - CallToolResult object with error
746+
* @param _contextStack - Optional Error object for stack context (unused, kept for compatibility)
747+
* @returns ErrorData with extracted message (no stack trace)
748+
*/
749+
function captureCallToolResultError(
750+
result: any,
751+
_contextStack?: Error,
752+
): ErrorData {
753+
// Extract message from content array
754+
const message =
755+
result.content
756+
?.filter((c: any) => c.type === "text")
757+
.map((c: any) => c.text)
758+
.join(" ")
759+
.trim() || "Unknown error";
760+
761+
const errorData: ErrorData = {
762+
message,
763+
type: "UnknownErrorType", // Can't determine actual type from CallToolResult
764+
platform: "javascript",
765+
// No stack or frames - SDK stripped the original error information
766+
};
767+
768+
return errorData;
769+
}
770+
711771
/**
712772
* Converts non-Error objects to string representation for error messages.
713773
*

0 commit comments

Comments
 (0)