modelcontextprotocol / modelcontextprotocol/typescript-sdk
Tool output validation fails when outputSchema is a Zod schema other than ZodObject
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 15h
- Merged PRs (30d)
- 4
Description
Describe the bug
Tool output validation fails with the following error when the tool's outputSchema is an optional, nullable, nullish, or union schema (or, most likely anything besides a plain object schema).
Cannot read properties of undefined (reading '_zod')
When validating output the SDK attempts to use normalizeObjectSchema, which returns undefined for anything besides object schemas.
To Reproduce
Steps to reproduce the behavior:
- Define an
outputSchemawith something other than a plain object orz.objectschema. - Implement the tool so that it returns
structuredContentthat conforms to this schema. - Invoke the tool.
// Works:
outputSchema: z.object({ data: z.string() })
// Fails:
outputSchema: z.object({ data: z.string() }).optional()
outputSchema: z.object({ data: z.string() }).nullable()
outputSchema: z.object({ data: z.string() }).nullish()
outputSchema: z.union([z.object({ data: z.string() }), z.object({ value: z.string() })])
Expected behavior
The SDK should be able to validate output based on Zod schemas which represent a JSON object, even if it is optional or a union of possible object schemas. Based on the spec, null is not a valid value for structuredContent, so nullable and nullish schemas should not be allowed, either through more restrictive typing of outputSchema or runtime validation with a clear error message.
Logs
at isZ4Schema ($PROJECT/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/zod-compat.js:46:21)
at safeParseAsync ($PROJECT/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/zod-compat.js:80:9)
at McpServer.validateToolOutput ($PROJECT/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/mcp.js:205:70)
at $PROJECT/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/mcp.js:135:28
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async wrappedHandler ($PROJECT/node_modules/@modelcontextprotocol/sdk/dist/cjs/server/index.js:131:32)
Additional context
"@modelcontextprotocol/sdk": "1.24.3",
"zod": "4.1.13"
I was expecting this to work based on https://github.com/modelcontextprotocol/typescript-sdk/pull/816 but it has possibly regressed with https://github.com/modelcontextprotocol/typescript-sdk/pull/1040
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/server/mcp.ts at validateToolOutput and read normalizeObjectSchema in src/server/zod-compat.ts, then reproduce the listed optional, nullable, nullish, and union schemas. Done means supported object-shaped schemas validate without the _zod error, while nullable or nullish structuredContent is rejected with a clear error consistent with the specification.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100