fix(server): prioritize zod issues and format them (#1503)

Co-authored-by: mozmo15 <mozmo@mail.com>
Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
This commit is contained in:
Mo 2026-03-31 14:20:35 +02:00 • committed by GitHub
commit 9edbab7a09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'@modelcontextprotocol/sdk': patch
---
Prioritize `error.issues[].message` over `error.message` in `getParseErrorMessage` so custom Zod error messages surface correctly. In Zod v4, `error.message` is a JSON blob of all issues, not a readable string.

View file

@ -188,6 +188,21 @@ export function normalizeObjectSchema(schema: AnySchema | ZodRawShapeCompat | un
return undefined;
}
function getDotPath(path: (string | number)[]) {
if (path.length === 0) {
return 'object root';
}
return path.reduce((acc, seg, index) => {
if (index === 0) {
return String(seg);
}
if (typeof seg === 'number') {
return `${acc}[${seg}]`;
}
return `${acc}.${seg}`;
}, '');
}
// --- Error message extraction ---
/**
* Safely extracts an error message from a parse result error.
@ -195,16 +210,21 @@ export function normalizeObjectSchema(schema: AnySchema | ZodRawShapeCompat | un
*/
export function getParseErrorMessage(error: unknown): string {
if (error && typeof error === 'object') {
// When present, prioritize zod issues and format as a message and path
if ('issues' in error && Array.isArray(error.issues) && error.issues.length > 0) {
return error.issues
.map((i: { message: string; path?: (string | number)[] }) => {
if (!i.path?.length) {
return i.message;
}
return `${i.message} at ${getDotPath(i.path)}`;
})
.join('\n');
}
// Try common error structures
if ('message' in error && typeof error.message === 'string') {
return error.message;
}
if ('issues' in error && Array.isArray(error.issues) && error.issues.length > 0) {
const firstIssue = error.issues[0];
if (firstIssue && typeof firstIssue === 'object' && 'message' in firstIssue) {
return String(firstIssue.message);
}
}
// Fallback: try to stringify the error
try {
return JSON.stringify(error);