Skip to content

zod listed in both dependencies and peerDependencies causes duplicate installs and TS type-incompatibility #2011

@Euaell

Description

@Euaell

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:

  1. bun init -y
  2. bun add @modelcontextprotocol/sdk@1.26.0 zod@4.4.2 typescript
  3. 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 }] }),
    )
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions