[BUG] Plugin update fails silently when MCP server holds open file handles; stale binary continues serving requests

Resolved 💬 1 comment Opened Jul 1, 2026 by jnbarlow Closed Jul 8, 2026

Summary

When a plugin is updated while its MCP server process is running, the new files are not copied to ~/.claude/plugins/data/<plugin>/. The metadata (installed_plugins.json) shows the correct version, but the actual binary on disk remains stale. Every tool call returns errors from old code until manually fixed by killing and restarting the MCP process + copying files yourself.

Reproduction Steps

  1. Install any plugin with an MCP server (stdio-based) at version X.Y.Z
  2. Start Claude Code session → MCP server spawns, holds open file handles to dist/index.js and other files under ~/.claude/plugins/data/<plugin>/mcp-server/
  3. Publish new version (X+1).Y.Z with changed code in the same paths
  4. Run claude plugin update <name> or wait for auto-update during session reload
  5. Observe: metadata updated to X.Y.Z, but files under data dir still contain old code

What Happens (Expected vs Actual)

Expected: New version is copied from cache → data dir and MCP server restarts with new code. Tool calls work correctly.

Actual: File copy fails silently because Node.js holds open file descriptors to the running binary. Old process continues serving requests with stale code. Every tool call returns errors even though metadata says latest version is installed.

Root Cause

The plugin updater copies files from ~/.claude/plugins/cache/<author>/<name>/vX.Y.Z/ to ~/.claude/plugins/data/<plugin-id>/. On Linux, when a Node.js process has open file handles (which the MCP server does for its own binary), in-place overwrites fail silently. The copy tool skips locked files without logging an error or updating status.json.

Additionally, there is no mechanism to kill and restart MCP servers after plugin updates — even if you bounce Claude Code entirely, stale files remain on disk so the new process loads old code again.

Impact

  • Silent failure: User sees correct version in claude plugin list but gets errors from tools. No indication that update failed mid-copy.
  • No workaround without manual intervention: Killing Claude Code does NOT fix it (stale files persist). Must manually kill MCP process, copy new files to data dir, then restart session.
  • Affects ALL plugins with persistent MCP servers, not just one plugin — any stdio-based MCP server that holds open file handles will exhibit this behavior.

Suggested Fixes

  1. Kill and restart affected MCP servers during update: Before copying new files, terminate processes for the updated plugin. Copy files to a temp directory first, then rename atomically (rename is atomic on same filesystem; avoids partial-copy race conditions). Restart MCP server with new code after copy completes successfully.
  2. Add claude mcp restart <name> command: Allow hot-reloading individual MCP servers without bouncing the entire session for debugging plugin updates and verifying changes in development workflows.
  3. Log errors when file copy fails during update instead of silently skipping locked files — user should know their update partially failed so they can take action.

Environment

  • Claude Code version: (check with claude -v)
  • Platform: Linux (WSL2)
  • Affected plugin: Any stdio-based MCP server plugin

View original on GitHub ↗

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