[BUG] /mcp` modal freezes TUI hard on WSL2 — only reproducible without `--debug

Resolved 💬 4 comments Opened Apr 24, 2026 by Release88 Closed May 20, 2026

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?

On Ubuntu 24.04 / WSL2 with Claude Code 2.1.119 (native install, Bun runtime), opening the /mcp modal hard-freezes the TUI: Enter, Esc, arrow keys, and Ctrl-C all become unresponsive. SIGINT is not processed. The only recovery is Ctrl-Z + kill -9 <pid>.

Critical clue: the bug does NOT reproduce when Claude Code is started with --debug. Same user, same config, same terminal, same session — /mcp works normally under --debug and freezes hard without it. This points to a timing-sensitive render loop where synchronous log output (only present in --debug) inadvertently breaks a bad state-update cycle.

Kernel-side inspection of a frozen process confirms it is not deadlocked on I/O and not in a CPU busy loop — the main thread repeatedly returns to epoll_wait while the process writes the TTY at ~30 Hz. Classic signature of a React/Ink render loop that re-schedules itself every frame, starving keyboard input processing.

Environment:

  • Claude Code 2.1.119 (latest on npm as of this report)
  • Install method: native (~/.local/share/claude/versions/2.1.119)
  • Runtime: Bun (confirmed via thread names: Bun Pool 0-7, HeapHelper, JITWorker)
  • Ubuntu 24.04 on WSL2, kernel 6.6.87.2-microsoft-standard-WSL2
  • Windows Terminal
  • Only ONE MCP server configured (npx -y @aashari/mcp-server-atlassian-bitbucket, stdio, status connected)
  • ENABLE_CLAUDEAI_MCP_SERVERS=false is set, so no cloud connectors in the list

Not a duplicate of #27367 (2-3s lag, different mechanism), #4232 (slash command latency), #23016 (Windows 11 startup freeze), or #19988 (freeze on large MCP responses). This is specifically about the /mcp modal hard-freezing with a single server, only when --debug is off.

What Should Happen?

Opening /mcp should render the server list and immediately respond to keyboard input (Enter to select, Esc to close, Ctrl-C to abort), regardless of whether Claude Code was started with --debug. Behavior must not depend on --debug being enabled.

Error Messages/Logs

No error is printed: the TUI renders the menu successfully and then silently becomes unresponsive. Because `--debug` is off when the bug reproduces, there are no debug logs to attach — this is part of what makes the bug hard to diagnose from user logs.

Instead, here is a **kernel-side snapshot** captured on a live frozen process (PID 1376, `claude --resume`, 35s elapsed, stuck on `/mcp`):

### Threads


$ ps -T -p 1376 -o tid,stat,%cpu,wchan:20,comm
  TID STAT %CPU WCHAN                COMMAND
 1376 Sl+  10.8 do_epoll_wait        claude         <- main thread
 1377 Sl+   0.4 futex_wait_queue     claude
 1378 Sl+   1.0 futex_wait_queue     HeapHelper
 1379 Sl+   1.0 futex_wait_queue     HeapHelper
 1380 Sl+   0.9 futex_wait_queue     HeapHelper
 1381 Sl+   0.9 futex_wait_queue     HeapHelper
 1382 Sl+   0.9 futex_wait_queue     HeapHelper
 1383 Sl+   0.9 futex_wait_queue     HeapHelper
 1384 Sl+   0.9 futex_wait_queue     HeapHelper
 1385 Sl+   2.2 futex_wait_queue     JITWorker
 1386-1399 Sl+ ~0 futex_wait_queue    Bun Pool 0-7
 1397 Sl+   0.0 do_epoll_wait        HTTP Client
 1445 Sl+   0.0 wait_woken           File Watcher


### Process state


$ cat /proc/1376/status | grep -E 'State|Threads|ctxt'
State: S (sleeping)
Threads: 20
voluntary_ctxt_switches:    28428    <- in ~35s of uptime = ~810/s
nonvoluntary_ctxt_switches: 36


### I/O activity (delta over 3 seconds)


rchar:       +11306 bytes   (~3.7 KB/s reads from TTY/sockets)
wchar:       +7759  bytes   (~2.6 KB/s writes to TTY)
syscr:       +333           (~111 read syscalls/s)
syscw:       +97            (~32 write syscalls/s)   <- TTY redraw at ~30 fps
read_bytes:  +0             (no disk reads)
write_bytes: +0             (no disk writes)


### Main thread wchan sampled 5 times over 1.5s


do_epoll_wait
do_epoll_wait
do_epoll_wait
do_epoll_wait
do_epoll_wait


### FDs of interest


 5 × anon_inode:[timerfd]       <- Bun timers
 3 × anon_inode:[eventpoll]
 3 × anon_inode:[eventfd]
13 × socket                     <- MCP stdio pipes + keep-alive HTTPS to Anthropic
 6 × /dev/pts/4                 <- TTY (stdin/stdout/stderr)


### Interpretation

- **Not a syscall deadlock**: main thread is in `do_epoll_wait`, not in a blocking syscall.
- **Not a CPU-bound busy loop**: `nonvoluntary_ctxt_switches` is tiny (36), CPU is ~20%.
- **App IS actively writing the TTY at ~30 fps** (`syscw` ~32/s, `wchar` ~2.6 KB/s) with zero disk I/O → the modal is continuously redrawing.
- **Input is being read** (`syscr` ~111/s) but never produces visible state transitions.
- High voluntary context switch rate (~810/s) consistent with a frame loop yielding between every tick.

This is the signature of a React/Ink render loop that keeps re-scheduling re-renders within every frame (state update inside effect/render → new render → new tick), starving the input handler. Under `--debug`, synchronous `console.log` / `process.stderr.write` calls yield the main thread at different points, which breaks whatever microtask ordering is required to trigger the loop — a textbook Heisenbug.

Steps to Reproduce

  1. On Ubuntu 24.04 WSL2, install Claude Code 2.1.119 (native install).
  2. In ~/.claude/settings.json set "env": { "ENABLE_CLAUDEAI_MCP_SERVERS": "false" } (optional, just to reduce the server list to one).
  3. Configure at least one MCP server. Example (stdio, npm-based):

``bash
claude mcp add bitbucket -s local \
-e BITBUCKET_USERNAME=... \
-e BITBUCKET_APP_PASSWORD=... \
-e BITBUCKET_WORKSPACE=... \
-- npx -y @aashari/mcp-server-atlassian-bitbucket
``

  1. Start Claude Code without --debug:

``bash
cd <any project dir>
claude # or: claude --resume
``

  1. At the prompt, type /mcp and press Enter.
  2. The modal renders showing bitbucket · ✔ connected.
  3. Press Enter, Esc, or Ctrl-C — nothing responds. The only exit is Ctrl-Z followed by kill -9 <pid>.

Control (does NOT reproduce):

  • Start with claude --debug instead. Same config, same terminal, same session — /mcp works normally, navigation and Esc respond immediately.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.119

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

_No response_

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗