Skip to content

fix: resolve Zod v4 toJSONSchema crash on z.record(z.unknown())#4

Open
samcolmanetti wants to merge 1 commit intoobra:mainfrom
samcolmanetti:fix-zod-v4-tools-list
Open

fix: resolve Zod v4 toJSONSchema crash on z.record(z.unknown())#4
samcolmanetti wants to merge 1 commit intoobra:mainfrom
samcolmanetti:fix-zod-v4-tools-list

Conversation

@samcolmanetti
Copy link
Copy Markdown

Problem

The MCP server connects and initializes successfully, but tools/list returns an internal error — silently hiding all 14 tools from clients.

The root cause is that Zod v4's toJSONSchema() crashes on z.record(z.unknown()) in the kg_create_node tool schema:

TypeError: Cannot read properties of undefined (reading '_zod')
    at process (zod/v4/core/to-json-schema.js:33:24)
    at Module.recordProcessor (zod/v4/core/json-schema-processors.js:432:37)

z.unknown() in Zod v4 lacks the _zod metadata that toJSONSchema expects. The MCP SDK (v1.27+) calls toJSONSchema() on every tool schema during tools/list, so this single schema issue breaks all tool registration.

Fix

Replace z.record(z.unknown()) with z.record(z.string(), z.any()) in kg_create_node's frontmatter parameter. z.any() is semantically equivalent but has the _zod metadata that toJSONSchema requires.

Tests

Added test/mcp-schemas.test.ts with two cases:

  • Verifies the fixed schema serializes to valid JSON Schema
  • Documents the upstream Zod v4 bug (z.record(z.unknown()) throws)

Fixes #2

z.record(z.unknown()) crashes Zod v4's toJSONSchema() because
z.unknown() lacks the _zod metadata the serializer expects. The MCP
SDK calls toJSONSchema() on every tool schema during tools/list, so
this silently hides all tools from clients.

Replace with z.record(z.string(), z.any()) which is semantically
equivalent and serializes correctly.

Add regression test that verifies the fixed schema serializes and
documents the upstream Zod v4 bug.

Fixes obra#2
@m3talux
Copy link
Copy Markdown

m3talux commented May 10, 2026

+1 — applied this locally on macOS and tools/list now returns all 14 kg_* tools cleanly. Same root cause hit independently in #7 (the second issue tracking this bug).

Worth flagging that minor nit on the PR description: in zod v4, z.unknown() actually does have _zod metadata — the crash isn't from that. It's that z.record(singleArg) in v4 is parsed as z.record(key=singleArg, value=undefined), so _zod.def.valueType is undefined and the JSON Schema processor dereferences it. Doesn't change the fix (still correct), just the explanation. Either z.record(z.string(), z.any()) or z.record(z.string(), z.unknown()) works.

Would be great to get this merged — it's been five weeks and the broken tools/list makes the plugin unusable as an MCP server on any install that pulls zod ≥ 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP tools/list fails: z.record(z.unknown()) crashes Zod v4's toJSONSchema

2 participants