{"record":{"id":"aee61afdab69ca6d","repo":"thedotmack/claude-mem","slug":"mcp-server-cjs-contains-a-bun-only-bunrequiremat","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/build-hooks.js","lineNumber":525,"sourceCode":"      define: {\n        '__DEFAULT_PACKAGE_VERSION__': `\"${version}\"`\n      },\n      banner: {\n        js: '#!/usr/bin/env node'\n      }\n    });\n\n    stripHardcodedDirname(`${hooksDir}/${MCP_SERVER.name}.cjs`);\n\n    fs.chmodSync(`${hooksDir}/${MCP_SERVER.name}.cjs`, 0o755);\n    const mcpServerStats = fs.statSync(`${hooksDir}/${MCP_SERVER.name}.cjs`);\n    console.log(`✓ mcp-server built (${(mcpServerStats.size / 1024).toFixed(2)} KB)`);\n\n    const mcpBundleContent = fs.readFileSync(`${hooksDir}/${MCP_SERVER.name}.cjs`, 'utf-8');\n    const bunRequireRegex = /require\\(\\s*[\"']bun:[a-z][a-z0-9_-]*[\"']\\s*\\)/;\n    const bunRequireMatch = mcpBundleContent.match(bunRequireRegex);\n    if (bunRequireMatch) {\n      throw new Error(\n        `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.`\n      );\n    }\n    const zodRequireRegex = /require\\(\\s*[\"']zod(?:\\/[^\"']*)?[\"']\\s*\\)/;\n    const zodRequireMatch = mcpBundleContent.match(zodRequireRegex);\n    if (zodRequireMatch) {\n      throw new Error(\n        `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.`\n      );\n    }\n\n    const MCP_SERVER_MAX_BYTES = 600 * 1024;\n    if (mcpServerStats.size > MCP_SERVER_MAX_BYTES) {\n      console.warn(\n        `⚠️  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).`\n      );\n    }\n","sourceCodeStart":507,"sourceCodeEnd":543,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/scripts/build-hooks.js#L507-L543","documentation":"A bundle-hygiene guard over the built MCP server (hooks/<name>.mcp-server.cjs). After esbuild bundles src/servers/mcp-server.ts, the build scans the output for require('bun:*') calls. The MCP server runs under Node (e.g. Claude Desktop), which has no bun:* modules, so any such require proves a transitive import dragged in worker-service.ts or another Bun-only module (DatabaseManager/ChromaSync). The fix is to sever the offending import chain, not to stub bun at runtime.","triggerScenarios":"Adding an import in src/servers/mcp-server.ts (or src/services/worker-spawner.ts) that transitively reaches a module importing 'bun:sqlite'/'bun:test'/etc. The esbuild bundle then carries the require('bun:...') and this guard fires. Cross-ref PR #1645 which introduced the isolation.","commonSituations":"Refactor that makes the MCP server import a shared service that itself imports DatabaseManager. Adding a utility to worker-spawner.ts that pulls in a Bun-only helper. A new feature that needs DB access from the MCP server path.","solutions":["Audit imports in src/servers/mcp-server.ts and src/services/worker-spawner.ts for anything that transitively touches SQLite/Chroma/DatabaseManager.","Move the shared logic into a node-safe module with no Bun imports, and have both worker-service.ts and mcp-server.ts depend on that, OR pass data across the worker/MCP boundary via IPC/HTTP instead of importing.","Keep worker-spawner.ts lightweight — it must not import anything that touches Bun-only modules (the error message states this contract explicitly).","Rebuild; the guard passes when no require('bun:*') remains in the bundle."],"exampleFix":"// before (src/services/worker-spawner.ts) — pulls a Bun-only helper\nimport { queryObservations } from './worker-service.js';\n\n// after — keep the spawner node-safe; MCP server gets data via the worker HTTP API instead\nimport { spawn } from 'child_process';\n// no DB imports here; mcp-server.ts calls worker /api/* endpoints","handlingStrategy":"validation","validationCode":"// After building, scan the bundle yourself to catch bun:* leakage early:\nconst out = fs.readFileSync('hooks/mcp-server.cjs','utf8');\nif (/require\\(\\s*[\"']bun:[a-z][a-z0-9_-]*[\"']\\s*\\)/.test(out)) {\n  throw new Error('Bun-only require leaked into mcp-server bundle');\n}","typeGuard":"// Node-safe module marker: a module that must not import bun:*\n// Add a lint rule forbidding bun:* imports in src/servers/** and src/services/worker-spawner.ts.","tryCatchPattern":"// Build-time only. Fix the import graph — do not patch the bundle.\n// Move shared logic into a node-safe module or call the worker over HTTP from the MCP server.","preventionTips":["Keep src/services/worker-spawner.ts free of any import that transitively touches SQLite/Chroma/DatabaseManager.","Add an eslint boundary rule (no-restricted-imports) banning bun:* in the MCP server's import graph.","When adding an import to mcp-server.ts, mentally trace it to ensure it doesn't reach worker-service.ts."],"tags":["build","verification","bundle","bun","node","mcp-server","pr-1645"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}