claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] MCP servers not properly terminated when Claude Code exits, causing orphaned processes

Open noomz opened this issue 6 months ago • 6 comments

Environment

  • Platform (select one):
    • [x] Anthropic API
    • [ ] AWS Bedrock
    • [ ] Google Vertex AI
    • [ ] Other:
  • Claude CLI version: 1.0.18 (Claude Code)
  • Operating System: macOS Darwin 24.5.0
  • Terminal: Terminal/zsh

Bug Description

Claude Code does not properly clean up MCP server processes when exiting, leading to orphaned processes that continue consuming system resources indefinitely. These processes accumulate over multiple sessions and are not cleaned up even when MCP servers are removed from configuration.

Steps to Reproduce

  1. Configure one or more MCP servers using claude mcp add <name> <command>
  2. Start Claude Code and use it normally (any session that might initialize MCP servers)
  3. Exit Claude Code normally
  4. Check running processes with ps aux | grep mcp
  5. Observe orphaned MCP server processes still running
  6. Optional: Try claude mcp remove <name> - processes still persist

Expected Behavior

MCP server processes should be gracefully terminated when Claude Code exits. All spawned MCP server processes should be cleaned up, leaving no orphaned processes consuming system resources.

Actual Behavior

MCP server processes remain running as orphaned processes after Claude Code exits. These processes:

  • Continue consuming system resources (CPU, memory)
  • Accumulate over time with each Claude Code session
  • Are not cleaned up even when running claude mcp remove <server-name>
  • Persist across system restarts in some cases

Additional Context

Evidence from testing:

  • Found 40+ orphaned MCP server processes from previous Claude Code sessions
  • Processes dating back several days (some running since Monday/Tuesday)
  • Process types include:
    • Docker containers: docker run -i --rm mcp/time, mcp/github, mcp/memory, etc.
    • Python processes: chroma-mcp, cli-mcp-server
    • Node.js processes: context7-mcp

Example orphaned processes (sanitized): user 90260 0.0 0.0 411858096 12272 s001 S+ 11:19AM 0:00.56 docker run -i --rm mcp/time user 88027 0.0 0.0 411869888 12224 ?? S 11:18AM 0:00.53 docker run -i --rm mcp/time user 54415 0.0 0.0 411896512 4576 ?? S Tue12PM 0:02.82 docker run -i --rm mcp/time user 90680 0.0 0.0 411871728 10912 ?? S Mon11AM 0:04.81 docker run -i --rm mcp/time user 54413 0.0 0.0 411889136 4080 ?? S Tue12PM 0:02.74 docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN=*** mcp/github user 54418 0.0 0.0 411896816 4128 ?? S Tue12PM 0:02.85 docker run --rm -i --mount type=bind,src=/Users/user/Projects/workspace,dst=/projects/workspace mcp/git

Impact:

  • Resource leak with long-running orphaned processes
  • Potential system performance degradation over time
  • User confusion when debugging MCP server issues
  • Accumulating Docker containers consuming disk space

Potential root cause: The MCP protocol specification includes a graceful shutdown phase, but Claude Code appears to not properly invoke cleanup handlers during application exit to terminate spawned MCP server child processes.

noomz avatar Jun 11 '25 09:06 noomz

We have a fix on the way!

ashwin-ant avatar Jun 11 '25 18:06 ashwin-ant

This should be fixed in 1.0.21. Thanks for reporting @noomz!

ashwin-ant avatar Jun 13 '25 13:06 ashwin-ant

I am on version 1.0.27 and seem to have this same issue. I have dozens of node processes. I am on the developer beta of macOS, is that an issue?

cbusillo avatar Jun 18 '25 17:06 cbusillo

I can confirm this issue still exists on Claude Code v1.0.31 with a custom MCP server. Additional context: The same custom MCP server is properly cleaned up when used with GitHub Copilot (process terminates correctly when stopping the server), which indicates that:

My MCP server correctly handles SIGINT termination signals The issue is specific to Claude Code's MCP process management, not a general MCP server problem

This suggests Claude Code is not sending the proper termination signals to MCP server child processes on exit, while other MCP clients (like GitHub Copilot) handle this correctly. Environment:

Claude Code version: v1.0.31 MCP Server: Custom server (properly handles SIGINT as verified with GitHub Copilot) Platform: macOS 15.5

The bug persists across multiple versions (original report was v1.0.18), indicating this hasn't been resolved yet.

CoreyWinkelmannPP avatar Jun 23 '25 14:06 CoreyWinkelmannPP

Same with v1.0.35. MCP server is a docker container that is persisted until I shut it down and delete it. A new container is instantiated with each call to claude command.

mstllc avatar Jun 26 '25 18:06 mstllc

Thanks, we'll look into this again.

ashwin-ant avatar Jun 27 '25 04:06 ashwin-ant

Hi all, please update to 1.0.38 and let me know if the issue persists. This should be much more robust now.

ashwin-ant avatar Jul 01 '25 02:07 ashwin-ant

Checking in here. Is this working for everyone? @CoreyWinkelmannPP @mstllc @noomz

ashwin-ant avatar Jul 05 '25 17:07 ashwin-ant

@ashwin-ant working for me on macOS 26 and Claude Code 1.0.43. Love CC, keep up the great work!

cbusillo avatar Jul 05 '25 21:07 cbusillo

@ashwin-ant This is happening for me on 1.0.51. My MCP server handles SIGINT fine if I launch it directly with npx, but not when I use the same npx command in .mcp.json with claude code. It does work if I configure the mcp server to launch directly from node_modules/.bin/the-bin instead of via npx / pnpm dlx.

As far as I can tell, claude is sending two back-to-back SIGINT signals, then waits 90ms, and then sends two back-to-back SIGTERM signals. For some reason when running through a wrapper like npx it seems like this isn't enough time and my actual MCP server doesn't get the SIGINT signal.

sbking avatar Jul 14 '25 21:07 sbking

Actually, even running the binary directly via the binary in node_modules doesn't work when claude is run in --print mode. I can't get claude to kill my MCP server process at all when run in --print mode.

sbking avatar Jul 14 '25 23:07 sbking

@ashwin-ant I did some digging, it looks like when run in --print mode, claude code isn't sending SIGINT or SIGTERM to my MCP server, it's just closing the stdin stream which leaves the MCP server running if there were any other active handlers

sbking avatar Jul 15 '25 17:07 sbking

@sbking nice catch on --print mode! We have a fix on the way. Are you seeing this in interactive mode too still?

ashwin-ant avatar Jul 15 '25 19:07 ashwin-ant

Still seeing this in interactive mode on latest version 1.0.73 (Windows)

Pimzino avatar Aug 12 '25 15:08 Pimzino

Still seeing this happening in 1.0.84

jgrichardson avatar Aug 19 '25 22:08 jgrichardson

Still seeing this happening in 1.0.85

neogenz avatar Aug 20 '25 06:08 neogenz

Still seeing this on v2.0.29

khandy-lively avatar Oct 30 '25 17:10 khandy-lively