thedotmack/claude-mem · critical · Error

mcp-server.cjs contains external ${zodRequireMatch[0]}. Clau

Error message

mcp-server.cjs contains external ${zodRequireMatch[0]}. Claude Desktop can launch this bundle without plugin node_modules available, so Zod must be bundled into the MCP server.

What it means

Companion guard to [7], scanning the built mcp-server.cjs for require('zod') or require('zod/...'). Claude Desktop launches this bundle without the plugin's node_modules on the module resolution path, so any external Zod require would fail at MCP startup. Zod (used for tool/schema validation) must be bundled into the CJS file by esbuild, not left as an external dependency.

Source

Thrown at scripts/build-hooks.js:532

    stripHardcodedDirname(`${hooksDir}/${MCP_SERVER.name}.cjs`);

    fs.chmodSync(`${hooksDir}/${MCP_SERVER.name}.cjs`, 0o755);
    const mcpServerStats = fs.statSync(`${hooksDir}/${MCP_SERVER.name}.cjs`);
    console.log(`✓ mcp-server built (${(mcpServerStats.size / 1024).toFixed(2)} KB)`);

    const mcpBundleContent = fs.readFileSync(`${hooksDir}/${MCP_SERVER.name}.cjs`, 'utf-8');
    const bunRequireRegex = /require\(\s*["']bun:[a-z][a-z0-9_-]*["']\s*\)/;
    const bunRequireMatch = mcpBundleContent.match(bunRequireRegex);
    if (bunRequireMatch) {
      throw new Error(
        `mcp-server.cjs contains a Bun-only ${bunRequireMatch[0]} call. This means a transitive import in src/servers/mcp-server.ts pulled in code from worker-service.ts (or another module that touches DatabaseManager/ChromaSync). The MCP server runs under Node and cannot load bun:* modules. Audit recent imports in src/servers/mcp-server.ts and src/services/worker-spawner.ts — the spawner module is intentionally lightweight and MUST NOT import anything that touches SQLite or other Bun-only modules. See PR #1645 for context.`
      );
    }
    const zodRequireRegex = /require\(\s*["']zod(?:\/[^"']*)?["']\s*\)/;
    const zodRequireMatch = mcpBundleContent.match(zodRequireRegex);
    if (zodRequireMatch) {
      throw new Error(
        `mcp-server.cjs contains external ${zodRequireMatch[0]}. Claude Desktop can launch this bundle without plugin node_modules available, so Zod must be bundled into the MCP server.`
      );
    }

    const MCP_SERVER_MAX_BYTES = 600 * 1024;
    if (mcpServerStats.size > MCP_SERVER_MAX_BYTES) {
      console.warn(
        `⚠️  mcp-server.cjs is ${(mcpServerStats.size / 1024).toFixed(2)} KB (advisory budget ${(MCP_SERVER_MAX_BYTES / 1024).toFixed(0)} KB). If this jumped unexpectedly, a transitive import may have pulled worker-service.ts or another heavy module into the MCP bundle (see #1645).`
      );
    }

    console.log(`\n🔧 Building context generator...`);
    await build({
      entryPoints: [CONTEXT_GENERATOR.source],
      bundle: true,
      platform: 'node',
      target: 'node18',
      format: 'cjs',

View on GitHub (pinned to d768ba3643)

Solutions

  1. In the esbuild config for MCP_SERVER, ensure 'zod' is NOT in the external list (or set bundle:true with no matching external entry) so Zod is inlined.
  2. After changing config, re-run node scripts/build-hooks.js and confirm the scan finds no require('zod...') in the built .cjs.
  3. If bundle size is a concern, prefer tree-shaking or a lighter schema lib over marking zod external.
  4. Verify the MCP server still starts under a host with no node_modules: the bundle must be self-contained.

Example fix

// before — esbuild config marks zod external
esbuild.build({ entryPoints:['src/servers/mcp-server.ts'], external:['zod'], ... })

// after — bundle zod in so the .cjs is self-contained
esbuild.build({ entryPoints:['src/servers/mcp-server.ts'], /* no external:zod */ ... })
Defensive patterns

Strategy: validation

Validate before calling

// Confirm Zod is inlined (no external require survives):
const out = fs.readFileSync('hooks/mcp-server.cjs','utf8');
if (/require\(\s*["']zod(?:\/[^"']*)?["']\s*\)/.test(out)) {
  throw new Error('zod must be bundled, not external, in mcp-server.cjs');
}

Try / catch

// Build-time only. Fix the esbuild config: remove 'zod' from the external list
// for the MCP_SERVER bundle. Do not suppress.

Prevention

When it happens

Trigger: esbuild is configured with `external: ['zod']` (or a wildcard external that matches zod) when bundling the MCP server, so the require call survives into the output. Adding a new external dependency declaration that accidentally covers zod.

Common situations: A bundler config change marks zod external to shrink the bundle. A dependency update that re-exports zod. Marking all of node_modules external for convenience.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/d5ce1ba2648daf77. Report an issue: GitHub.