TS2589: Type instantiation is excessively deep and possibly infinite after upgrading the SDK?This TypeScript error can appear when upgrading to newer SDK versions that support Zod v4 (for example, from @modelcontextprotocol/sdk 1.22.0 to 1.23.0) and your project ends up with multiple zod versions in the dependency tree.
When there are multiple copies or versions of zod, TypeScript may try to instantiate very complex, cross-version types and hit its recursion limits, resulting in TS2589. This scenario is discussed in GitHub issue
#1180.
To diagnose and fix this:
zod versions:
npm ls zod or npm explain zod, pnpm list zod or pnpm why zod, or yarn why zod and check whether more than one version is installed.zod version:
zod use a compatible version range so that your package manager can hoist a single copy.zod at the workspace root and using compatible ranges in individual packages.overrides / resolutions to force a single zod version if some transitive dependencies pull in a different one.Once your project is using a single, compatible zod version, the TS2589 error should no longer occur.
globalThis.crypto) for client authentication in older Node.js versions?The SDK’s OAuth client authentication helpers (for example, those in src/client/auth-extensions.ts that use jose) rely on the Web Crypto API exposed as globalThis.crypto. This is especially important for client credentials and JWT-based authentication flows used by
MCP clients.
globalThis.crypto is available by default.globalThis.crypto may not be defined by default. In this repository we polyfill it for tests (see vitest.setup.ts), and you should do the same in your app if it is missing – or alternatively, run Node with --experimental-global-webcrypto as per your
Node version documentation. (See https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#crypto )If you run clients on Node.js versions where globalThis.crypto is missing, you can polyfill it using the built-in node:crypto module, similar to the SDK's own vitest.setup.ts:
import { webcrypto } from 'node:crypto';
if (typeof globalThis.crypto === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).crypto = webcrypto as unknown as Crypto;
}
For production use, you can either:
globalThis.crypto is available by default (recommended), orThe SDK ships several runnable server examples under src/examples/server. The root README.md contains a curated Server examples table that links to each scenario (stateful/stateless Streamable HTTP, JSON-only mode, SSE/backwards compatibility, elicitation, sampling,
tasks, and OAuth demos), and src/examples/README.md includes commands and deployment diagrams for running them.