[BUG] Desktop app sessions are declared "non-interactive" (isTTY heuristic) in the MCP-auth notice, misrouting OAuth remediation
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
In the Claude Desktop app, the harness appends this to its MCP-authentication notice in the system prompt:
The following MCP servers require authentication before their tools can be used:<servers>This session is non-interactive, so Claude cannot run the OAuth flow here. Tell the user that these servers need to be authorized — for claude.ai connectors, via their claude.ai connector settings; for other servers, viaclaude mcpor/mcpin an interactive session — and that the capability is unavailable until they do.
The session was fully attended — a human at the keyboard, typing turns in the desktop app in real time. The model relayed the claim to the user (as instructed), the user replied "but it is interactive, I'm here now", and was correct.
Root cause
The gate appears to be a TTY check. In the desktop app the agent is spawned as a subprocess with no pty:
| Signal | Value |
| --- | --- |
| CLAUDE_CODE_ENTRYPOINT | claude-desktop |
| __CFBundleIdentifier | com.anthropic.claudefordesktop |
| stdin isTTY | false |
| CLAUDE_CODE_ENABLE_ASK_USER_QUESTION_TOOL | true |
So the check uses "no terminal is attached" as a proxy for "no human is attached." Those are equivalent in a piped/-p CLI invocation; they are not equivalent in a GUI app, where there is no pty precisely because the UI is not a terminal.
The last row is the internal contradiction: the same session enables AskUserQuestion — the tool whose entire purpose is asking the user a question and waiting — and then declares the user absent. Both cannot be true.
Two distinct harms
- False statement to the user. The model tells an attended user that the session is unattended. Users who don't push back accept it.
- The remediation is wrong for this entrypoint. It routes the user to
claude mcp//mcp"in an interactive session" — but the desktop app is the surface that performs connector OAuth. It sends users to a terminal for something the app in front of them handles, and can leave them believing a connector is unauthorizable in the client they're already using.
What Should Happen?
Either:
- Gate on the actual entrypoint rather than
isTTY—claude-desktop(and any GUI client) is attended by construction; or - Keep the capability statement but drop the interactivity claim. "OAuth cannot be completed from this agent context" is accurate and sufficient. "This session is non-interactive" is a claim about the user's presence that the harness cannot infer from a pty check.
A reasonable consistency rule: any session where AskUserQuestion is enabled should never be described as non-interactive.
Reproduction
- Open the Claude Desktop app with at least one unauthenticated MCP server configured.
- Ask the model to use a tool from that server.
- It reports the session is non-interactive and directs you to authorize elsewhere.
- Ask it to check
CLAUDE_CODE_ENTRYPOINTand whether stdin is a TTY —claude-desktop, and not a TTY.
Related
anthropics/claude-code#77327 — the autonomous-operation prompt ("the user is not watching in real time") injected into attended CLI/VS Code sessions. Same misclassification family, different injection site and different entrypoint, so filing separately rather than as a comment there. If maintainers see one shared gate behind both, they may be worth fixing together.
Environment
- Claude Code 2.1.221, Agent SDK 0.3.221
- Claude Desktop app on macOS 26.5.2 (Apple Silicon)
- Model: Opus 5