KBCodeKB
pnpmUnverified

Fix MCP TypeScript SDK 'Type instantiation is excessively deep' TS2589 Error with ToolCallback in Claude Desktop, Cursor, and VS Code

When importing `ToolCallback<Args>` from `@modelcontextprotocol/sdk` in TypeScript projects, the compiler throws `Type instantiation is excessively deep and possibly infinite.ts(2589)`. This occurs when the project has conflicting Zod versions — typically Zod 3 and Zod 4 coexisting in the dependency tree. The MCP SDK < 1.23.0 pins `zod@^3.23.8`, but if any dependency (or the project itself) installs Zod 4, TypeScript's type resolution overflows due to incompatible generics between versions. The error grinds IDEs to a halt and blocks builds. ## Agent Decision Tree 1. Check current MCP SDK version: `npm list @modelcontextprotocol/sdk` → if < 1.23.0, go to step 2; else go to step 5 2. Determine if project uses Zod 4: `npm list zod` → if v4 present, go to Solution A; else go to Solution B 3. Check for duplicate Zod versions: `npm ls zod --all` → if multiple versions, go to Solution C 4. Verify TypeScript config: check `moduleResolution` in tsconfig → if `node` (legacy), go to Solution D 5. Agent successfully diagnosed — execute the most applicable solution below

Symptoms

  • TypeScript error TS2589: 'Type instantiation is excessively deep and possibly infinite' when importing ToolCallback from @modelcontextprotocol/sdk
  • IDE hangs or freezes when saving TypeScript files importing MCP SDK types
  • Build fails with TS2589 after upgrading Zod to v4
  • Error persists even after pinning Zod to a single version
  • Multiple Zod versions visible in `npm ls zod --all` output
  • Occurs specifically with MCP SDK versions 1.16.0 through 1.22.x

Error signatures

Type instantiation is excessively deep and possibly infinite.ts(2589)
ToolCallback<Args>
@modelcontextprotocol/sdk/dist/esm/server/mcp.d.ts

Possible causes

  • MCP SDK < 1.23.0 depends on zod@^3.23.8 only — Zod 4 types are structurally incompatible with Zod 3 generic chains, causing TypeScript's generic instantiation depth to exceed the 50-type limit when both versions coexist in the same compilation context
  • Package manager hoisting (npm/yarn/pnpm) causes a silent version mismatch: even when `npm list` shows zod@3.x at the top level, a hoisted zod@4.x from another dependency can win at runtime type resolution. This happens because TypeScript resolves types from the FIRST matching zod installation in the node_modules tree, not from the declared dependency — a 'silent mismatch' that npm list won't reveal
  • Zod 4's internal type restructuring (e.g., ZodTypeAny generics in v4 vs v3) produces infinitely-recursive type resolution when Zod 3 types flow through Zod 4 generic constraints or vice versa. The MCP SDK's ToolCallback<Args> type is particularly vulnerable because it chains multiple Zod schema generics through a single callback signature
  • TypeScript's moduleResolution: 'node' (legacy) triggers different module resolution paths that can load Zod types from unexpected locations — a node_modules/zod at a deeper level may be resolved before the project-level zod, compounding the version conflict

Solutions

Solution C: Update tsconfig to modern moduleResolution (Zod maintainer recommendation)

risk: lowgithubpublished

Legacy `moduleResolution: 'node'` can cause TypeScript to resolve Zod types from incorrect locations in node_modules. Switching to `bundler` or `node16` ensures types resolve from the correct package copy. This is a supplementary fix recommended by Zod maintainer @colinhacks (Zod #5222).

  1. Pre-check: Run `npx tsc --showConfig 2>/dev/null | grep moduleResolution` to see current setting
  2. If current is 'node' (legacy), change tsconfig.json: set `moduleResolution` to `bundler` and `module` to `esnext`
  3. Run `npx tsc --noEmit 2>&1; echo exit=$?` to verify

Commands

npx tsc --showConfig 2>/dev/null | grep moduleResolution
npx tsc --noEmit 2>&1 | grep -c TS2589
npx tsc --noEmit 2>&1; echo exit=$?

Config examples

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler"
  }
}

Risks

  • Changing moduleResolution may break other type imports in legacy CJS codebases
  • Requires TypeScript >= 5.0 (verify with `npx tsc --version`)

Verification

  • Step 1: Run `npx tsc --version` → expect >= 5.0.0 (bundler resolution requires TS 5+)
  • Step 2: Run `npx tsc --showConfig 2>/dev/null | grep moduleResolution` → expect 'bundler' or 'node16'
  • Step 3: Run `npx tsc --noEmit 2>&1; echo exit=$?` → expect exit code 0, no TS2589 errors
0 verified0 failed

Solution B: Pin Zod to v3.x with package manager overrides (for Zod 3-only projects)

risk: lowgithubpublished

If migrating to Zod 4 is not feasible, enforce Zod v3 across the entire dependency tree using npm overrides, yarn resolutions, or pnpm overrides. This prevents any transitive dependency from installing Zod 4, eliminating the type conflict at its source.

  1. Pre-check: Run `npm ls zod --all 2>/dev/null | grep 'zod@4'` to confirm Zod 4 is present in the tree
  2. Add `overrides` (npm), `resolutions` (yarn), or `pnpm.overrides` (pnpm) to package.json forcing zod@3.25.76
  3. Delete lockfile and node_modules: `rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml`
  4. Reinstall: `npm install` (or yarn/pnpm equivalent)
  5. Verify: `npm ls zod --all 2>/dev/null | grep -c 'zod@4'` should return 0

Commands

npm ls zod --all 2>/dev/null | grep 'zod@4' | head -5
npm install zod@3.25.76
npm ls zod --all 2>/dev/null | grep -c 'zod@4'
rm -rf node_modules package-lock.json && npm install && npx tsc --noEmit 2>&1; echo exit=$?

Config examples

{
  "overrides": {
    "zod": "3.25.76"
  }
}
{
  "resolutions": {
    "zod": "3.25.76"
  }
}
{
  "pnpm": {
    "overrides": {
      "zod": "3.25.76"
    }
  }
}

Risks

  • Dependencies that genuinely require Zod 4 features (e.g., `z.parse()` with v4-only APIs) will break at runtime
  • Overrides affect ALL dependencies, not just MCP SDK — test thoroughly after applying

Verification

  • Step 1: Run `npm ls zod --all 2>/dev/null` → expect ALL entries show zod@3.x.x (zero entries for zod@4.x.x)
  • Step 2: Run `npx tsc --noEmit 2>&1; echo exit=$?` → expect exit code 0, no TS2589 in output
  • Step 3: If exit code is non-zero, run `npx tsc --noEmit 2>&1 | grep TS2589` → if TS2589 still present, check node_modules for residual Zod 4 with `find node_modules -name 'zod' -type d -maxdepth 3`
0 verified0 failed

Solution A: Upgrade MCP SDK to >= 1.23.0 (Recommended — staff-confirmed fix)

risk: lowofficialpublished

MCP SDK v1.23.0 added official Zod 4 support (`zod: ^3.25 || ^4.0`). Upgrading resolves the type instantiation error by allowing a single consistent Zod version across all dependencies. This is the maintainer-recommended fix confirmed by @mattzcarey (MCP SDK team) in the GitHub issue closure on Nov 27, 2025.

  1. Pre-check: Run `npm list @modelcontextprotocol/sdk 2>&1` to verify current version is < 1.23.0
  2. Pre-check: Run `npm view @modelcontextprotocol/sdk version` to confirm latest available version
  3. Upgrade: `npm install @modelcontextprotocol/sdk@latest` (should install >= 1.29.0 as of June 2026)
  4. Ensure Zod is also updated: `npm install zod@latest`
  5. Clear TypeScript build cache: `rm -rf node_modules/.cache/tsbuildinfo`
  6. Verify fix: `npx tsc --noEmit 2>&1; echo exit=$?` — must show exit code 0 with no TS2589 errors

Commands

npm list @modelcontextprotocol/sdk 2>&1
npm view @modelcontextprotocol/sdk version
npm install @modelcontextprotocol/sdk@latest zod@latest
pnpm update @modelcontextprotocol/sdk zod --latest
yarn upgrade --latest @modelcontextprotocol/sdk zod
rm -rf node_modules/.cache/tsbuildinfo && npx tsc --noEmit 2>&1; echo exit=$?

Config examples

{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",
    "zod": "^4.1.6"
  }
}

Risks

  • Breaking changes between MCP SDK 1.22 and 1.23+ — review changelog before upgrading
  • Zod 4 has breaking changes from Zod 3 — existing schema definitions may need migration (see Zod migration guide)

Verification

  • Step 1: Run `npm list @modelcontextprotocol/sdk 2>&1` → expect output showing version >= 1.23.0 (e.g., '@modelcontextprotocol/sdk@1.29.0')
  • Step 2: Run `npm list zod 2>&1` → expect exactly ONE zod entry (no duplicate versions). If multiple versions appear (e.g., zod@3.24.3 AND zod@4.1.6), abort and apply Solution C first
  • Step 3: Run `npx tsc --noEmit 2>&1; echo exit=$?` → expect stdout: no TS2589 errors, exit code 0. If exit code is non-zero and errors include TS2589, the Zod version conflict persists
0 verified0 failed

Agent JSON

Canonical machine-readable representation of this issue:

{
  "issue_id": "5835467b-b0b1-42c6-9ca2-c8a408b42723",
  "slug": "fix-mcp-typescript-sdk-type-instantiation-is-excessively-deep-ts2589-error-with-toolcallback-in-claude-desktop-cursor-an-rhiff3",
  "verification_status": "unverified",
  "canonical_json": "https://codekb.dev/v1/issues/fix-mcp-typescript-sdk-type-instantiation-is-excessively-deep-ts2589-error-with-toolcallback-in-claude-desktop-cursor-an-rhiff3"
}
← Back to all issuesPowered by CodeKB