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.

> **Doing this backwards on v1 fails quietly.** Passing a v2-style complete `z.object(...)` into
> the v1 positional `server.tool()` slot — which expects a raw shape — publishes an empty
> `inputSchema` on v1.12.0 through v1.26.0, so clients drop every argument; the same schema passed
> to `registerTool()` on v1.12.0 through v1.21.0 makes `tools/list` throw
> `Cannot read properties of null (reading '_def')`. See the
> [troubleshooting page](../troubleshooting.md) for the searchable symptoms.

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
26 changes: 26 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,31 @@ Align everything on one Zod 4 version. When a transitive dependency pins another

`npm ls zod` reporting a single version means the duplicate is gone and the error with it.

## `tools/list` returns an empty `inputSchema`, or fails with `reading '_def'`

Both symptoms come from passing a complete `z.object({ ... })` where the **v1** positional
`server.tool(name, description, schema, handler)` API expects a **raw Zod shape** —
`{ name: z.string() }`, with no `z.object()` wrapper.

- With `server.tool()`, v1.12.0 through v1.26.0 publish `{"type":"object"}` with **no properties**
and raise nothing: `tools/list` looks correct, but clients send no arguments and your handler
receives an empty object. v1.28.0 and later reject the wrapped shape at registration instead.
- Passing that same complete schema to v1 `registerTool()` fails `tools/list` on v1.12.0 through
v1.21.0 with `MCP error -32603: Cannot read properties of null (reading '_def')`; v1.22.0 and
later normalize it.

Use a raw shape with the v1 positional API:

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

In **v2** the contract inverts: `registerTool()` takes a config object whose `inputSchema` is a
[Standard Schema](https://standardschema.dev/) object such as `z.object({ name: z.string() })`.
The [v1 to v2 migration guide](./migration/upgrade-to-v2.md#standard-schema-objects-raw-shapes-deprecated)
covers the full call-shape change.

## `ReferenceError: crypto is not defined`

The OAuth client helpers sign and verify through the Web Crypto API at `globalThis.crypto`. Every `@modelcontextprotocol/*` package requires Node.js 20, where that global is always defined — this error means the process is running on an older runtime (Node.js 18 and earlier).
Expand Down Expand Up @@ -172,6 +197,7 @@ HTTP SSE streams emit a `: keepalive` comment every 15 seconds by default so cli
- Every heading on this page is the exact message you searched for.
- On stdio, `stdout` carries JSON-RPC; log with `console.error`.
- `TS2589` means two `zod` copies in the dependency tree.
- v1 positional `server.tool()` takes a raw Zod shape; a `z.object()` there publishes an empty schema (or crashes `registerTool()` with `reading '_def'`). v2 `registerTool()` takes a Standard Schema object.
- The SDK raises `ERA_NEGOTIATION_FAILED` and `METHOD_NOT_SUPPORTED_BY_PROTOCOL_VERSION` locally — neither is a wire error.
- Server SSE and the Authorization Server helpers live in `@modelcontextprotocol/server-legacy`.

Expand Down
Loading