Preview MCP `preview_start` ignores `runtimeExecutable` and crashes on corepack-wrapped pnpm under Node 20

Resolved 💬 1 comment Opened May 26, 2026 by roastfmla Closed May 26, 2026

Summary

mcp__Claude_Preview__preview_start does not honour the runtimeExecutable field in .claude/launch.json. Regardless of what executable I name, the spawn path goes through a corepack-wrapped pnpm shim under the MCP server's Node 20.19.6 runtime, which then crashes with ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING because the MCP's vm context has no dynamic-import callback registered.

Two distinct bugs are stacked; (1) is the real one.

Environment

  • macOS (Darwin 25.5.0)
  • Node 20.19.6 and Node 24.11.0 both installed via nvm
  • pnpm 11.2.2 in use for the affected workspace (installed via corepack)
  • Preview MCP server itself runs under Node 20.19.6 (visible in the crash trailer)

Repro

.claude/launch.json configured to bypass pnpm/corepack entirely by naming Node 24 directly and passing the resolved pnpm.mjs as the first arg:

{
  "version": "0.0.1",
  "configurations": [
    {
      "name": "myapp-dev",
      "runtimeExecutable": "/Users/<user>/.nvm/versions/node/v24.11.0/bin/node",
      "runtimeArgs": [
        "/Users/<user>/.cache/node/corepack/v1/pnpm/11.2.2/bin/pnpm.mjs",
        "--filter",
        "@myorg/myapp",
        "dev"
      ],
      "port": 3000
    }
  ]
}

Call: preview_start name="myapp-dev".

Result, every time, regardless of what runtimeExecutable / runtimeArgs are set to:

node:internal/modules/esm/utils:272
  throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
        ^

TypeError [ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING]: A dynamic import callback was not specified.
    at importModuleDynamicallyCallback (node:internal/modules/esm/utils:272:9)
    at Object.<anonymous> (/Users/<user>/.cache/node/corepack/v1/pnpm/11.2.2/bin/pnpm.cjs:3:1)
    at Module2._compile (/Users/<user>/.nvm/versions/node/v20.19.6/lib/node_modules/corepack/dist/lib/corepack.cjs:16944:34)
    ...
Node.js v20.19.6

Why this is a bug

(1) preview_start does not honour runtimeExecutable. The crash trailer names pnpm.cjs and corepack.cjs running under Node 20.19.6 — but my launch.json explicitly says "use the Node 24 binary at this other path." The corepack shim should never have been on the spawn path at all. It looks like the MCP server runs its own pnpm preflight (probably to resolve workspace metadata or the script) before honouring the user-supplied executable.

(2) The MCP server's Node 20.19.6 vm context lacks an import-callback hook. The pnpm.cjs shim is effectively one line: import('./pnpm.mjs'). Compiling it through Module._compile() inside a vm context requires importModuleDynamicallyCallback to be set. The MCP server's runtime doesn't set one, so corepack-wrapped pnpm 11.2.2 crashes on every pnpm-using project under Node 20.x. An operator can work around this by upgrading Node, but (1) is what actually needs fixing.

Expected behaviour

preview_start reads .claude/launch.json, spawns runtimeExecutable with runtimeArgs (and cwd if set), and runs no additional pnpm/corepack preflight. The MCP server tracks the spawned PID + port for preview_list / preview_stop. If runtimeExecutable is set, trust the user's executable choice and don't touch corepack/pnpm at all.

Current workaround

Bash background launch via Node 24 directly. Server boots, but the MCP's preview iframe + preview_eval / preview_screenshot / preview_resize / preview_snapshot tools can't see it (different launch path → different serverId tracking). So every visual-verification flow that depends on the Preview MCP is unavailable in projects that use corepack-managed pnpm.

Notes

  • Affects any project that uses corepack-managed pnpm (the default install path now) on a machine where the Preview MCP server happens to be running under Node 20.x.
  • Fixing (1) alone is sufficient — once runtimeExecutable is honoured, the user can route around the vm import-callback issue by naming a Node binary they trust.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗