claude-code - 💡(How to fix) Fix Plugin MCP reconnect fails: ${CLAUDE_PLUGIN_ROOT} not substituted after /model or session reconnect

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When Claude Code reconnects a plugin's MCP server (e.g. after /model command or session restart), the ${CLAUDE_PLUGIN_ROOT} placeholder in the plugin's .mcp.json args is not substituted with the actual plugin root path. This causes the spawned node process to immediately exit with MODULE_NOT_FOUND, and Claude Code retries for 30 seconds before surfacing a timeout error.

Error Message

$ node '${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs' Error: Cannot find module '/path/to/project/${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs' code: 'MODULE_NOT_FOUND'

Root Cause

Hardcode the absolute path in the plugin's .mcp.json instead of using ${CLAUDE_PLUGIN_ROOT}. This is fragile (breaks on reinstall/path change) but confirms the substitution is the root cause.

Fix Action

Workaround

Hardcode the absolute path in the plugin's .mcp.json instead of using ${CLAUDE_PLUGIN_ROOT}. This is fragile (breaks on reinstall/path change) but confirms the substitution is the root cause.

Code Example

$ node '${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs'
Error: Cannot find module '/path/to/project/${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs'
    code: 'MODULE_NOT_FOUND'

---

{
  "mcpServers": {
    "my-plugin": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs"]
    }
  }
}
RAW_BUFFERClick to expand / collapse

Description

When Claude Code reconnects a plugin's MCP server (e.g. after /model command or session restart), the ${CLAUDE_PLUGIN_ROOT} placeholder in the plugin's .mcp.json args is not substituted with the actual plugin root path. This causes the spawned node process to immediately exit with MODULE_NOT_FOUND, and Claude Code retries for 30 seconds before surfacing a timeout error.

Steps to reproduce

  1. Install a plugin that registers an MCP server via .mcp.json using ${CLAUDE_PLUGIN_ROOT} in the args (standard plugin pattern)
  2. Start a Claude Code session — plugin MCP connects successfully on first load
  3. Run /model to switch models — triggers MCP reconnect
  4. Observe error: Failed to reconnect to plugin:<name>:<name>: MCP server "plugin:<name>:<name>" connection timed out after 30000ms

Expected behavior

${CLAUDE_PLUGIN_ROOT} substituted consistently on both initial connect and all subsequent reconnects.

Actual behavior

Initial connect: substitution works, MCP starts correctly (~26ms).
Reconnect: substitution skipped, node receives literal ${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs as the file path → MODULE_NOT_FOUND → immediate exit → 30s retry loop → timeout.

Diagnostics

Running the unsubstituted path directly:

$ node '${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs'
Error: Cannot find module '/path/to/project/${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs'
    code: 'MODULE_NOT_FOUND'

The substitution that works on first load does NOT happen on reconnect triggered by /model.

Environment

  • Claude Code version: 2.1.161
  • OS: Linux (CachyOS / Arch)
  • Node.js: v26.1.0
  • Plugin: local dev

Workaround

Hardcode the absolute path in the plugin's .mcp.json instead of using ${CLAUDE_PLUGIN_ROOT}. This is fragile (breaks on reinstall/path change) but confirms the substitution is the root cause.

Plugin .mcp.json (standard pattern that triggers the bug)

{
  "mcpServers": {
    "my-plugin": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/mcp-runtime.mjs"]
    }
  }
}

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

${CLAUDE_PLUGIN_ROOT} substituted consistently on both initial connect and all subsequent reconnects.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING