C:/Program Files/Git/mcp settings menu refuses to open in genuinely interactive terminal sessions — client-attachment check inherits the $CLAUDE_JOB_DIR-as-background-proxy defect from #59848
Summary
On Windows, every claude session — including ones with a real terminal actively attached and a user typing — is permanently tagged as a background/"spare" session in the daemon's own bookkeeping (roster.json: "source": "spare", no subsequent "claimed"/interactive transition ever recorded). This causes /mcp to refuse to open with "Can't open MCP settings in a background session," even while the user is mid-conversation in that exact session.
This is the same root defect identified and (partially) fixed in #59848 ("Interactive claude sessions are classified as background jobs post-2.1.139") — but that fix addressed only the worktree bgIsolation guard consumer. The /mcp gating logic added afterward (2.1.214, 2.1.216) checks "is a terminal/client attached" using the same unfixed signal, so it inherits the identical false positive.
Environment
- Claude Code CLI version: 2.1.220 (also reproduced on 2.1.212 before an in-session auto-update)
- OS: Windows 11 Pro (10.0.26200)
- Shell: PowerShell 7, direct
claudeinvocation, no wrapper/alias/launcher script - Daemon: transient, singleton per machine (
~/.claude/daemon.json,~/.claude/daemon.log,~/.claude/daemon/roster.json)
Repro
- Open PowerShell,
cdinto any project directory. - Run
claude(no flags). - Start a normal interactive conversation.
- Run
/mcp. - Observe: "Can't open MCP settings in a background session — use
/mcp enable|disable|reconnect <server>to steer, or run /mcp from an interactive terminal to authenticate." — despite this being exactly that interactive terminal.
Reproduces on a brand-new terminal + brand-new session every time, not just resumed/continued sessions.
Evidence
Process tree (Get-CimInstance Win32_Process) for the session in question:
claude.exe --bg-pty-host \\.\pipe\cc-daemon-<id>-pty-<session> <cols> <rows> -- claude.exe --session-id <uuid> --agent claude
└─ claude.exe --session-id <uuid> --agent claude (the actual interactive engine)
└─ node.exe <plugin mcp servers...>
Every session — even the very first one spawned right after a cold daemon start — is created via this --bg-pty-host path, not a standalone foreground process.
~/.claude/daemon/roster.json — every worker entry, regardless of how long the user has been actively typing into it, permanently carries:
"dispatch": {
"source": "spare",
...
}
No field anywhere in the schema records a "claimed by interactive client" transition. This is confirmed on sessions that had 20+ minutes of continuous interactive use at time of inspection.
~/.claude/daemon.log — representative sequence:
[supervisor] ─── daemon start ─── version=2.1.220 pid=29728 origin=transient
[bg] bg: control socket bound at \\.\pipe\cc-daemon-*-control
[bg] bg spawned 039ad304 (spare) <- first session on a cold daemon, still "(spare)"
Killing the daemon entirely (claude daemon stop --any) does not help: a fresh daemon starts on the next claude invocation and immediately spawns the new session via the identical (spare) path. There is no remaining non-daemon/foreground launch code path to fall back to.
Config/settings ruled out — confirmed clean, not the cause:
- No relevant key in
~/.claude/settings.jsonor~/.claude/settings.local.json(global or project-level). - No shell alias/wrapper shadowing
claude.exeon PATH. - No relevant env var (
CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MSset/unset made no difference). - No flag in
claude --help/claude daemon --helpto disable the daemon or spare pool.
Changelog timeline (CHANGELOG.md, newest-first):
2.1.208: "/install-github-appand the/mcpsettings menu no longer open in background sessions" (blanket block introduced)2.1.214: "Fixed/install-github-appand the/mcpsettings menu being blocked in agent-view sessions — they're now refused only in background sessions with no terminal attached" (intent: allow when a terminal is attached)2.1.216: "Background sessions:/mcpand/install-github-appnow park a 'needs input' request in the agent view when no client is attached" (further refinement, same intent)
By this stated intent, /mcp should work in the reproduction above, since a terminal is genuinely attached. It doesn't — because the "is a client attached" check appears to read the same source/template signal that #59848 already showed is set unconditionally by the daemon's spare-pool registration, not by actual attachment state.
Relationship to #59848
#59848 (closed 2026-05-27) diagnosed the general mechanism: since the warm-spare pool became "real" around v2.1.139, the daemon registers every session (not just genuine background jobs) and sets $CLAUDE_JOB_DIR unconditionally, which downstream consumers wrongly treat as "this is a background job." The maintainer's fix ("interactive sessions are no longer misclassified as background jobs") closed that issue, but — based on the roster.json evidence above, gathered fresh on 2.1.220 — the underlying signal defect is still present at the daemon level. It appears only the specific consumer raised in #59848 (the worktree bgIsolation guard) was patched; the /mcp//install-github-app gating logic added in the same era (2.1.208–2.1.216) was built on the same unfixed signal and never got an equivalent patch, or regressed independently.
Per #59848's own analysis (commenter kcarriedo), "is this background" collapses at least four orthogonal axes (TTY-attachment, spawn origin, persistence, isolation policy) into one signal. The /mcp gate needs axis 1 (TTY-attachment) specifically — the daemon needs to expose that as its own signal rather than deriving it from spare-pool registration state.
Suggested fix direction
Expose actual TTY/client-attachment as an independent, first-class signal in the daemon's worker bookkeeping (e.g., a clientAttached: bool or attachedAt: timestamp field in roster.json, flipped on real socket/PTY attach and cleared on detach) and have the /mcp//install-github-app gate (and any other "is this background" consumer) check that signal directly, instead of source/template/$CLAUDE_JOB_DIR.
Impact
Any Windows user launching claude directly from a terminal cannot use /mcp's interactive settings/auth flow at all, on any session, regardless of how long they've been actively working in it. Confirmed workaround: the desktop app is unaffected (does not go through this daemon/pty-host path).