Skip to content

TypeScript Compilation Memory Issues with @modelcontextprotocol/sdk #985

@NEDDL

Description

@NEDDL

Summary

The @modelcontextprotocol/sdk package causes severe memory consumption during TypeScript compilation, leading to out-of-memory (OOM) errors in CI/CD environments and even locally with constrained memory. This issue affects projects that import the SDK, particularly in containerized build environments.

Environment Details

Package Version

  • @modelcontextprotocol/sdk: ^1.18.2
  • TypeScript: 5.7.2
  • Node.js: 22.17.1
  • pnpm: 9.0.0

Project Context

  • Project Type: TypeScript monorepo with Turborepo
  • Architecture: Node.js backend (Fastify) with shared types package
  • Build Tool: TypeScript compiler (tsc)
  • CI Environment: GitLab CI with Kubernetes runners
  • Local Environment: macOS with 16GB RAM

Affected Imports

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

Problem Description

Memory Consumption Analysis

  • Expected: ~170MB for a 32-file TypeScript project (1,800 lines total)
  • Actual: 4GB+ memory usage leading to heap exhaustion
  • Root Cause: TypeScript compiler processes 430+ files instead of expected 32 files
  • Files breakdown:
    • Project source files: 32
    • MCP SDK type definitions: 104 .d.ts files
    • Total package size: 9.1MB
    • Additional transitive dependencies pulled in during type resolution

Error Symptoms

Local Development (512MB heap limit)

<--- Last few GCs --->
[88854:0x130008000] 15675 ms: Mark-Compact (reduce) 1020.8 (1047.8) -> 1020.0 (1043.8) MB

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

CI Environment (4GB heap limit)

<--- Last few GCs --->
[109:0xe7de000] 333165 ms: Mark-Compact 4037.9 (4128.7) -> 4022.3 (4128.9) MB
[109:0xe7de000] 336634 ms: Mark-Compact 4038.1 (4128.9) -> 4022.6 (4129.2) MB

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Stack Trace Analysis

The crash shows repeated InterpreterEntryTrampoline calls, indicating potential infinite recursion or circular dependency resolution during TypeScript compilation:

171: 0x101990ef0 Builtins_InterpreterEntryTrampoline [node]
172: 0x101990ef0 Builtins_InterpreterEntryTrampoline [node]
[... repeated 200+ times ...]

Attempted Solutions

1. Memory Limit Increases (❌ Failed)

  • Increased Node.js heap from 4GB to 5GB
  • Used Kubernetes high-memory runners (8GB+)
  • Result: Still hit OOM, just took longer

2. TypeScript Configuration Optimizations (❌ Insufficient)

{
  "compilerOptions": {
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "incremental": false,
    "declaration": false,
    "isolatedModules": true,
    "strict": false
  }
}
  • Result: Reduced memory slightly but still exceeded 4GB

3. Node.js Runtime Optimizations (❌ Insufficient)

NODE_OPTIONS="--max-old-space-size=4096 --gc-interval=50 --max-semi-space-size=64"
  • Result: Failed due to invalid flags, and valid flags didn't solve the core issue

Working Solution

TypeScript Compilation with --noCheck Flag

The only effective solution was to bypass type checking during the build process:

{
  "scripts": {
    "build": "NODE_OPTIONS=\"--max-old-space-size=1536\" tsc -p tsconfig.build.json --noCheck"
  }
}

Results:

  • ✅ Memory usage: 512MB (down from 4GB+)
  • ✅ Build time: ~18 seconds (acceptable)
  • ✅ Output: Proper JavaScript transpilation
  • ⚠️ Trade-off: No type checking during build (moved to separate lint step)

Impact Assessment

CI/CD Pipeline Impact

  • Build failures: 100% failure rate on standard and high-memory runners
  • Resource waste: Requiring oversized CI runners for simple TypeScript projects
  • Development velocity: Blocked deployments and feature development

Developer Experience Impact

  • Local development: Forced to use --noCheck workaround
  • Type safety: Had to separate type checking from build process
  • Debugging: Difficult to identify if issues are project-specific or package-related

Technical Analysis

File Resolution Explosion

Normal TypeScript compilation for our project:

# Expected files
find src -name "*.ts" | wc -l
# Output: 32

# Actual files processed by TypeScript with MCP SDK
tsc --listFiles | wc -l
# Output: 430+

Package Dependency Analysis

# MCP SDK type definitions
find node_modules/@modelcontextprotocol -name "*.d.ts" | wc -l
# Output: 104

# Package size
du -sh node_modules/.pnpm/@modelcontextprotocol+sdk@1.18.2
# Output: 9.1M

Reproduction Steps

  1. Create a TypeScript project with the MCP SDK dependency
  2. Import any module from @modelcontextprotocol/sdk
  3. Run TypeScript compilation with memory monitoring:
    NODE_OPTIONS="--max-old-space-size=1024" npx tsc --build
  4. Observe memory growth to 1GB+ for even minimal projects

Expected Behavior

TypeScript compilation should:

  • Process only necessary files for the specific imports used
  • Consume reasonable memory proportional to project size
  • Complete successfully on standard CI runners (2-4GB memory)
  • Not require --noCheck workarounds for basic functionality

Suggested Investigation Areas

  1. Type Definition Complexity: Review if type definitions can be simplified or split
  2. Circular Dependencies: Check for circular references in type definitions
  3. Import Strategy: Consider if barrel exports or deep imports cause different behavior
  4. TypeScript Compatibility: Test with different TypeScript versions for regressions
  5. Bundle Analysis: Analyze what specific files cause the memory explosion

Additional Context

This issue appears to be related to similar TypeScript memory problems reported in the ecosystem:

  • Complex type definitions causing exponential memory growth
  • Type resolution loops in certain package configurations
  • Known issues with TypeScript 5.x memory management in specific scenarios

The fact that --noCheck completely resolves the issue suggests the problem is specifically in the type checking/resolution phase rather than the transpilation phase.

Workaround Impact

While our workaround is functional, it has implications:

  • Reduced type safety: Build process no longer catches type errors
  • Increased complexity: Separate type checking step required
  • CI configuration: Special handling needed for affected packages
  • Developer confusion: Non-obvious solution to a common import

We would greatly appreciate investigation into this issue to restore normal TypeScript compilation capabilities for projects using the MCP SDK.

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