[BUG] disabledMcpServers with stdio plugin server causes silent exit(0)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Trigger: Any entry in disabledMcpServers referencing a real stdio plugin MCP server
Symptom: TUI renders, REPL mounts, then process exits with code 0
Root cause: Node.js event loop drains - process.stdin not keeping event loop alive
Proof: Adding a long-lived child process (sleep 120 hook) prevents the exit
Versions: Confirmed on 2.1.50 and 2.1.71
Related: #33992 (same symptom, different trigger - may share root cause)
What Should Happen?
Session should remain running and accept user input. Disabled MCP servers should simply not connect, with no effect on the REPL lifecycle.
Error Messages/Logs
No error messages. Debug log (--debug) shows normal startup, MCP connection failures for non-disabled servers, then the log silently ends. strace -e trace=signal confirms exit_group(0) with no signals received.
Steps to Reproduce
- Install any plugin that defines a stdio MCP server
- In ~/.claude.json, add the server name to disabledMcpServers for the project:
"projects": {
"/path/to/project": {
"disabledMcpServers": ["plugin:PLUGIN_NAME:SERVER_NAME"]
}
}
- Run claude interactively in that project
- TUI renders the welcome screen and REPL prompt, then exits with code 0 within seconds
Note: disabling HTTP/SSE transport servers does NOT trigger this. Only stdio transport.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.71
Platform
AWS Bedrock
Operating System
Other Linux
Terminal/Shell
Xterm
Additional Information
- Root cause: Node.js event loop drains. process.stdin is not keeping the event loop alive.
- Proof: Adding a SessionStart hook that runs sleep 120 (a long-lived child process) prevents the exit entirely. This confirms stdin is unref'd and external handles are the only thing keeping the process alive.
- The process survives exactly as long as other ref'd handles exist (MCP child processes, API TCP streams). When the last one closes, exit(0).
- Possibly related to #33992 (same symptom, different trigger) - may share the same underlying stdin/event loop issue.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗