Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/migration/upgrade-to-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,13 @@ are still **accepted via `@deprecated` overloads** on `registerTool`/`registerPr
(auto-wrapped with `z.object()`), and `completable()` accepts any `StandardSchemaV1`;
prefer wrapping explicitly. Zod v4, ArkType, and Valibot all implement the spec.

> **Do not apply the v2 style backwards on v1:** on SDK v1, `server.tool()`
> (and `registerTool` before 1.22) expects the **raw shape**, not `z.object(...)`.
> A `ZodObject` there crashes `tools/list` on v1 ≤ 1.21 and silently publishes
> an empty schema (arguments stripped) via `server.tool()` on v1 ≤ 1.26.
> If you backport v2 examples to a v1 server, unwrap to the raw shape — see
> [Troubleshooting](../troubleshooting.md#mcp-error--32603-cannot-read-properties-of-null-reading-_def).

For **optional completable arguments**, apply `.optional()` to the _result_ of
`completable()` — `completable(z.string(), cb).optional()`, not
`completable(z.string().optional(), cb)`. v2 resolves completion metadata on the schema
Expand Down
17 changes: 17 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ The Resource Server helpers did not move there: `requireBearerAuth`, `mcpAuthMet

HTTP SSE streams emit a `: keepalive` comment every 15 seconds by default so client body-idle timeouts and intermediaries do not terminate an otherwise idle connection. Configure the interval with `keepAliveMs` on the transport or `createMcpHandler`; set it to `0` to disable heartbeats.

## `MCP error -32603: Cannot read properties of null (reading '_def')`

On SDK v1, `server.tool()` (and `registerTool` before 1.22) expects a **Zod raw shape** — `{ name: z.string() }` — not a `ZodObject`. Passing `z.object({ name: z.string() })` fails without ever naming the mistake:

- v1 ≤ 1.21: `tools/list` crashes with this error.
- v1 ≤ 1.26 via `server.tool()`: no error anywhere, but the published schema is an empty `{"type":"object"}` — clients strip every argument and the handler receives none.
- v1 ≥ 1.28: registration throws a clear error, and `registerTool` has normalized `z.object()` since 1.22.

Fix the call site — unwrap to the raw shape:

```diff
- server.tool('greet', 'desc', z.object({ name: z.string() }), handler);
+ server.tool('greet', 'desc', { name: z.string() }, handler);
```

On v2 the direction reverses: `registerTool` takes schema objects (`z.object(...)`), with raw shapes only on deprecated overloads — see the [v1→v2 migration guide](./migration/upgrade-to-v2.md#standard-schema-objects-raw-shapes-deprecated).

## Recap

- Every heading on this page is the exact message you searched for.
Expand Down
Loading