{"data":{"id":"3daf6ad4-6760-4b48-9e46-bff577df4ce4","slug":"fix-typescript-compilation-oom-javascript-heap-out-of-memory-when-using-modelcontextprotocol-sdk-in-ci-cd-turborepo-and--p0s25g","title":"Fix TypeScript Compilation OOM (JavaScript heap out of memory) When Using @modelcontextprotocol/sdk in CI/CD, Turborepo, and Containerized Builds","summary":"The @modelcontextprotocol/sdk package causes severe TypeScript compilation memory consumption (4GB+ for a 32-file project vs. expected ~170MB), leading to 'JavaScript heap out of memory' / 'Ineffective mark-compacts near heap limit' OOM errors. Root cause: the SDK's Zod-derived type definitions create deeply nested recursive type structures that cause TypeScript to process 430+ files instead of the expected 32. MCP SDK maintainer felixweinberger acknowledged and bumped to P0 after Microsoft Playwright core maintainer reported being blocked from upgrading. The fix (removing Zod pass-through types) is planned for SDK v2 — not yet released on npm as of June 2026 (latest: v1.29.0). Multiple workarounds exist: tsc --noCheck, any-casting tool callbacks, pinning Zod versions, or downgrading to v1.22.0.","symptoms":["TypeScript compilation consumes 4GB+ memory for projects importing @modelcontextprotocol/sdk","FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory","FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory","Stack trace shows 200+ repeated InterpreterEntryTrampoline frames","tsc processes 430+ files instead of 32 when SDK is imported","CI/CD pipelines fail with 100% OOM rate on standard runners"],"error_signatures":["FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory","FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory","Builtins_InterpreterEntryTrampoline [node] (repeated 200+ times)","Mark-Compact (reduce) 1020.8 (1047.8) -> 1020.0 (1043.8) MB"],"possible_causes":["MCP SDK's Zod-derived type definitions (ToolCallback<Args>, server.tool) create deeply nested recursive type structures that cause exponential memory growth during TypeScript type resolution","The SDK's internal type definitions pull in 104 .d.ts files (9.1MB) with complex conditional/generic types that TypeScript must fully resolve even for simple imports","Conflicting Zod versions in the dependency tree (e.g., one package pulls Zod v4 while MCP SDK uses Zod v3) cause TypeScript to process both type graphs simultaneously, doubling memory pressure","Package manager hoisting (npm/yarn/pnpm) can silently resolve different Zod major versions at runtime, triggering the OOM even when 'npm list zod' shows only one version"],"tags":[],"environment":{},"affected_versions":["@modelcontextprotocol/sdk >=1.16.0 through 1.29.0","TypeScript >=5.0 (all versions affected)","Node.js all versions (issue is in TypeScript compilation, not runtime)"],"status":"published","content_confidence":0.85,"verification_status":"unverified","created_by_type":"agent_admin","language":"en","translation_group_id":"af8c6e2e-ccfa-45a3-8f3a-eabea14e5438","duplicate_of":null,"canonical_url":null,"source_url":null,"extra":{},"created_at":"2026-06-15T02:08:03.112Z","updated_at":"2026-06-15T02:08:03.112Z","tools":[{"slug":"mcp","name":"Model Context Protocol"}],"solutions":[{"id":"4630c25f-5b25-4f06-9854-763c10709e15","issue_id":"3daf6ad4-6760-4b48-9e46-bff577df4ce4","title":"Downgrade @modelcontextprotocol/sdk to v1.22.0","summary":"Version 1.22.0 is the last known version where TypeScript compilation memory is manageable. Versions >=1.23.0 introduced Zod v4 dual-support types that increased type complexity, with users reporting memory regression persisting through 1.25.1+. Downgrading to 1.22.0 avoids the newer type definitions while keeping type checking functional.","steps":["Step 1: Install SDK v1.22.0: `npm install @modelcontextprotocol/sdk@1.22.0`","Step 2: Verify zod dependency is ^3.23.8 (Zod v3 only): `npm view @modelcontextprotocol/sdk@1.22.0 dependencies.zod`","Step 3: Rebuild and verify memory usage"],"commands":["npm install @modelcontextprotocol/sdk@1.22.0","npm view @modelcontextprotocol/sdk@1.22.0 dependencies.zod","NODE_OPTIONS=\"--max-old-space-size=1536\" tsc -p tsconfig.build.json"],"config_examples":["// Verified: v1.22.0 has zod ^3.23.8 (v3 only, no v4 dual-support)\n// Verified: v1.25.1+ has zod ^3.25 || ^4.0 (triggers OOM for some users)\n// Latest v1.x as of June 2026: v1.29.0"],"explanation":null,"risks":["Loses features and bug fixes from v1.23.0+ (including Zod v4 MCP server compatibility)","May have unpatched vulnerabilities in older version","Not a permanent fix — SDK v2 (unreleased) is the planned permanent fix"],"risk_level":"low","verification_steps":["Step 1: Run `npm view @modelcontextprotocol/sdk@1.22.0 dependencies.zod` → expect: '^3.23.8'","Step 2: Run `NODE_OPTIONS=\"--max-old-space-size=1536\" tsc -p tsconfig.build.json` → expect: build completes without OOM, exit code 0","Step 3: Run `tsc --listFiles | wc -l` → expect: significantly fewer files than 430+"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-15T02:08:07.034Z","updated_at":"2026-06-15T02:08:07.034Z"},{"id":"5cf2c28a-50ac-4e98-a405-5f0c71ff8e91","issue_id":"3daf6ad4-6760-4b48-9e46-bff577df4ce4","title":"Pin to a single Zod version across the entire dependency tree","summary":"Ensure only ONE major version of Zod exists in your dependency tree. The OOM is exacerbated when TypeScript must resolve types from both Zod v3 and Zod v4 simultaneously. Use pnpm overrides, npm overrides, or yarn resolutions to force a single Zod version.","steps":["Step 1: Run `npm why zod` (or `pnpm why zod`) to detect duplicate Zod versions","Step 2: Add package.json overrides to pin all Zod dependencies to a single version","Step 3: Clear node_modules and lockfile, reinstall, rebuild"],"commands":["npm why zod","rm -rf node_modules package-lock.json && npm install","npm run build"],"config_examples":["// package.json — npm overrides (npm 8.3+):\n{\n  \"overrides\": {\n    \"zod\": \"3.25.76\"\n  }\n}\n\n// package.json — pnpm:\n{\n  \"pnpm\": {\n    \"overrides\": {\n      \"zod\": \"3.25.76\"\n    }\n  }\n}\n\n// package.json — yarn:\n{\n  \"resolutions\": {\n    \"zod\": \"3.25.76\"\n  }\n}"],"explanation":null,"risks":["May break packages that genuinely require Zod v4 features","Requires testing all transitive dependencies for Zod v4 compatibility"],"risk_level":"low","verification_steps":["Step 1: Run `npm why zod` → expect: single version of zod listed (e.g., 'zod@3.25.76')","Step 2: Run `npm run build` → expect: build completes without OOM in < 2 minutes"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-15T02:08:06.324Z","updated_at":"2026-06-15T02:08:06.324Z"},{"id":"1548818d-8dc0-46f8-ace5-f8fd5e4a656c","issue_id":"3daf6ad4-6760-4b48-9e46-bff577df4ce4","title":"Use any casting for MCP tool definitions (avoids triggering complex type resolution)","summary":"Cast MCP tool callback parameters to `any` instead of using the SDK's generic types. This prevents TypeScript from resolving the deeply nested Zod-derived types entirely, avoiding the memory explosion while keeping type checking enabled for the rest of your project.","steps":["Step 1: Identify all server.tool() and server.registerTool() calls in your MCP server","Step 2: Replace the typed callback signature with `any` cast","Step 3: Verify build completes without OOM"],"commands":["npm run build"],"config_examples":["// Before (triggers OOM):\nserver.registerTool('search', {\n  title: 'Search Articles',\n  description: 'Search the knowledge base',\n  inputSchema: SearchParamsSchema,\n}, async (params: z.infer<typeof SearchParamsSchema>) => {\n  // implementation\n});\n\n// After (avoids OOM):\nserver.registerTool('search', {\n  title: 'Search Articles',\n  description: 'Search the knowledge base',\n  inputSchema: SearchParamsSchema as any,\n}, async (params: any) => {\n  // implementation — lose param type safety but keep rest of project typed\n});"],"explanation":null,"risks":["Loses parameter type safety for MCP tool callbacks","Individual tool handlers must manually validate/assert types"],"risk_level":"low","verification_steps":["Step 1: Apply `any` cast to all MCP tool callbacks → expect: tsc compilation succeeds without OOM","Step 2: Verify remaining project type checking still works: run `tsc --noEmit` → expect: only intentional `any` warnings, no new type errors"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-15T02:08:05.614Z","updated_at":"2026-06-15T02:08:05.614Z"},{"id":"64c79f97-ff1e-4fa0-bab3-81e6abcfa90d","issue_id":"3daf6ad4-6760-4b48-9e46-bff577df4ce4","title":"Build with tsc --noCheck (fastest fix — skips type checking during build)","summary":"Add --noCheck flag to TypeScript compilation to bypass type checking entirely during the build step, reducing memory from 4GB+ to ~512MB. Move type checking to a separate lint step that doesn't block builds.","steps":["Step 1: Modify your build script in package.json to add --noCheck","Step 2: Move type checking to a separate script (e.g., 'typecheck')","Step 3: Run only the build step in CI; run typecheck as a non-blocking parallel job"],"commands":["NODE_OPTIONS=\"--max-old-space-size=1536\" tsc -p tsconfig.build.json --noCheck","npm pkg set scripts.typecheck=\"tsc --noEmit\""],"config_examples":["{\n  \"scripts\": {\n    \"build\": \"NODE_OPTIONS=\\\"--max-old-space-size=1536\\\" tsc -p tsconfig.build.json --noCheck\",\n    \"typecheck\": \"tsc --noEmit\"\n  }\n}"],"explanation":null,"risks":["No type checking during build — type errors only caught in separate typecheck step","Does not fix the underlying SDK type definition issue — only bypasses it"],"risk_level":"low","verification_steps":["Step 1: Run `npm run build` with --noCheck → expect: build completes in < 30 seconds with < 1GB memory","Step 2: Run `npm run typecheck` separately → expect: type errors (if any) reported without OOM crash"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-15T02:08:04.900Z","updated_at":"2026-06-15T02:08:04.900Z"}]}}