Describe the bug
@modelcontextprotocol/sdk@1.26.0 declares zod in BOTH dependencies and
peerDependencies. With bun (and pnpm under default hoisting, npm in some
configs) this causes a nested node_modules/@modelcontextprotocol/sdk/node_modules/zod
to be installed alongside the consumer's top-level zod, even when the
consumer's version satisfies the SDK's range.
The result: TypeScript sees two distinct $ZodType class declarations (one per
copy) and treats them as nominally incompatible. Schemas built from the
consumer's zod (e.g. z.string().optional()) fail to satisfy the
AnySchema = z3.ZodTypeAny | z4.$ZodType type that registerTool's
inputSchema parameter expects — even though both copies are the same library
at the same major version.
To Reproduce
Steps to reproduce the behavior:
bun init -y
bun add @modelcontextprotocol/sdk@1.26.0 zod@4.4.2 typescript
- Create
src/server.ts:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { z } from 'zod'
const server = new McpServer({ name: 'demo', version: '0.0.1' })
server.registerTool(
'echo',
{ inputSchema: { msg: z.string() } },
async ({ msg }) => ({ content: [{ type: 'text', text: msg }] }),
)
bun x tsc --noEmit
Expected behavior
Typecheck passes. The consumer's zod should satisfy the AnySchema slot
because the SDK's compat layer already accepts both z3.ZodTypeAny and
z4.$ZodType, and the consumer's schemas are valid z4.$ZodType values.
Logs
src/server.ts:7:24 - error TS2322: Type 'ZodString' is not assignable to type 'AnySchema'.
Type 'ZodString' is missing the following properties from type
'ZodType<any, any, any>': _type, _parse, _getType, _getOrReturnCtx, and 7 more.
7 { inputSchema: { msg: z.string() } },
~~~~~~~~~~
ls node_modules/@modelcontextprotocol/sdk/node_modules/zod/package.json
shows the nested copy is installed (e.g. 4.3.6) alongside the top-level (4.4.2).
Additional context
Workaround consumers have to apply (this is what bit us):
// package.json
"overrides": { "zod": "" }
followed by deleting bun.lock + reinstalling so the existing resolution is
re-evaluated.
Proposed fix: remove "zod" from dependencies and keep it only in
peerDependencies. The compat shim (dist/esm/server/zod-compat.d.ts) already
handles both v3 and v4 via the consumer-provided copy, so the SDK doesn't
need its own bundled zod.
Repo: https://github.com/modelcontextprotocol/typescript-sdk
SDK version: 1.26.0
Bun version: 1.3.12
TypeScript: 5.9.3
Zod (top): 4.4.2
Zod (nested): 4.3.6
Describe the bug
@modelcontextprotocol/sdk@1.26.0declareszodin BOTHdependenciesandpeerDependencies. With bun (and pnpm under default hoisting, npm in someconfigs) this causes a nested
node_modules/@modelcontextprotocol/sdk/node_modules/zodto be installed alongside the consumer's top-level
zod, even when theconsumer's version satisfies the SDK's range.
The result: TypeScript sees two distinct
$ZodTypeclass declarations (one percopy) and treats them as nominally incompatible. Schemas built from the
consumer's
zod(e.g.z.string().optional()) fail to satisfy theAnySchema = z3.ZodTypeAny | z4.$ZodTypetype thatregisterTool'sinputSchemaparameter expects — even though both copies are the same libraryat the same major version.
To Reproduce
Steps to reproduce the behavior:
bun init -ybun add @modelcontextprotocol/sdk@1.26.0 zod@4.4.2 typescriptsrc/server.ts:bun x tsc --noEmitExpected behavior
Typecheck passes. The consumer's zod should satisfy the AnySchema slot
because the SDK's compat layer already accepts both z3.ZodTypeAny and
z4.$ZodType, and the consumer's schemas are valid z4.$ZodType values.
Logs
src/server.ts:7:24 - error TS2322: Type 'ZodString' is not assignable to type 'AnySchema'.
Type 'ZodString' is missing the following properties from type
'ZodType<any, any, any>': _type, _parse, _getType, _getOrReturnCtx, and 7 more.
7 { inputSchema: { msg: z.string() } },
~~~~~~~~~~
ls node_modules/@modelcontextprotocol/sdk/node_modules/zod/package.json
shows the nested copy is installed (e.g. 4.3.6) alongside the top-level (4.4.2).
Additional context
Workaround consumers have to apply (this is what bit us):
// package.json
"overrides": { "zod": "" }
followed by deleting bun.lock + reinstalling so the existing resolution is
re-evaluated.
Proposed fix: remove "zod" from dependencies and keep it only in
peerDependencies. The compat shim (dist/esm/server/zod-compat.d.ts) already
handles both v3 and v4 via the consumer-provided copy, so the SDK doesn't
need its own bundled zod.
Repo: https://github.com/modelcontextprotocol/typescript-sdk
SDK version: 1.26.0
Bun version: 1.3.12
TypeScript: 5.9.3
Zod (top): 4.4.2
Zod (nested): 4.3.6