claude.ai-hosted MCP connectors intermittently expose zero tools in headless launchd/claude -p sessions
Bug report: claude.ai MCP connectors expose zero tools in headless claude -p sessions
Summary
claude.ai-hosted MCP connectors (Microsoft 365, Teams, Fellow, monday.com, Salesforce,
Kiteworks) report "Connected" via claude mcp list and work instantly in an interactive
Claude Code session, but consistently expose zero callable tools when the exact same
account runs a headless claude -p invocation launched via macOS launchd. This has
recurred 4 times in 5 days and survives a full ToolSearch retry budget (4 attempts, 30s
apart) inside the run.
Environment
- Claude Code CLI, headless mode (
claude -p ... --output-format json --allowedTools "...") - macOS launchd LaunchAgent (
com.timfreestone.cos-daily-brief), runs as the logged-in user,
not a login item, no attached TTY
- Model:
claude-sonnet-5 - Connectors: 6x
claude.ai-hosted MCP servers (OAuth-linked to Microsoft 365, Teams,
Fellow.ai, monday.com, Salesforce V1, Kiteworks Content MCP)
Timeline of occurrences
- 2026-09-17: Kiteworks connector blocked by an ungranted permission gate all run
- 2026-09-18: monday.com connector failed to connect at all
- 2026-09-21 06:55 PT: all 6 connectors simultaneously showed "Connected" in
claude mcp list but exposed zero usable tools in the headless session; Kiteworks-rag
server also timed out on every retry
- 2026-09-21 08:12 PT: reproduced again in a manual
launchctl kickstarttest, ~80
minutes after the first occurrence, same result
What we ruled out
- Not a transient "still connecting" race. The daily-brief prompt already treats
"still connecting" as non-terminal and retries ToolSearch up to 4x with 30s sleeps
(~2 min budget) per connector before giving up. All 6 connectors still failed
simultaneously through that full budget, both occurrences.
- Not a bad/expired CLI auth token. Generated a fresh long-lived token via
claude setup-token, verified it independently with a zero-cost, connector-free
claude -p "reply OK" call (is_error: false, clean result) — the Anthropic API
auth layer is fine. Re-ran the real headless job with this verified-good token:
identical zero-connector-tools result.
- Not account-level connector health.
claude mcp list, run interactively on the
same Mac under the same account at the same time, shows all 6 connectors "Connected"
and they respond immediately to real calls (calendar search, board search, meeting
search all returned live data in an interactive session run minutes apart from the
failing headless run).
Working theory
The claude binary's own internal auth-health checks (visible via strings on the CLI)
distinguish two separate auth surfaces:
- "Connected to the Anthropic API (api.anthropic.com)"
- "Signed in to claude.ai" / "claude.ai subscription active"
CLAUDE_CODE_OAUTH_TOKEN (from claude setup-token) appears to satisfy only the first.
The claude.ai-hosted MCP connectors seem to require the second — likely tied to an
interactive, device/browser-linked session — which a detached launchd background
process cannot obtain, regardless of which token is exported into its environment.
Reproduction
- Interactively:
claude mcp list→ all connectors show Connected. Call any connector
tool (e.g. outlook_calendar_search) → works immediately.
- Headlessly, same account, same Mac: `claude -p "<prompt using ToolSearch then a
connector tool>" --allowedTools "ToolSearch,mcp__claude_ai_Microsoft_365__outlook_calendar_search"launchd` LaunchAgent (no TTY, no GUI login item) → ToolSearch
launched via a
reports the tool "still connecting" through the full retry budget, then gives up;
the connector call never succeeds.
- Setting
CLAUDE_CODE_OAUTH_TOKENin the headless process's environment (via
claude setup-token, verified valid) does not change the outcome.
Ask
Is there a supported way to get claude.ai-hosted MCP connector access working inside a
headless/background Claude Code session (no TTY, launched by a scheduler, not a GUI
login item)? If this is a hard platform boundary (connectors require an
interactively-linked session by design), that would be useful to know explicitly so we
can stop trying client-side auth fixes and design around it instead (e.g., calling the
underlying services' own APIs directly rather than through claude.ai's MCP brokering
for anything that must run unattended).
Where to file
https://github.com/anthropics/claude-code/issues
Update 2026-09-22 — investigated, partially resolved, root cause still open
Found and fixed one real, confirmed bug: producer/.env's CLAUDE_CODE_OAUTH_TOKEN
had gone blank (still exported as an empty string by run-daily-brief.sh, which is
different from unset). Initially suspected as THE root cause of this outage.
That suspicion did not survive more rigorous re-testing the same day. Direct
reproduction attempts -- with the token blank, with it fully unset, with onlyANTHROPIC_API_KEY set, and via a genuine detached launchd LaunchAgent (no TTY, no
GUI login item, matching this job's real runtime exactly) -- all resolved and called
real claude.ai connectors (M365, Fellow, monday.com all individually confirmed)
cleanly and consistently. An earlier batch of failures traced to firing severalclaude -p processes back-to-back with no gap in the test harness itself, not to any
auth env var. So: the blank token is a real bug (now fixed, see below) but is
unproven as the cause of the sustained 9/17-9/22 outage, and the original working
theory above (claude.ai session vs Anthropic-API auth-surface mismatch) is also
unconfirmed by this session's tests -- every connector worked fine today regardless
of which auth surface was active.
Net: the underlying flakiness that produced 6 outage incidents in 6 days was not
reproducible on 2026-09-22 under any tested condition. It may have been transient /
server-side and already cleared, or it may recur under conditions not captured by
these tests (time of day, load, something else). This report should stay open with
Anthropic per the Ask above; treat the fix below as a mitigation, not a proof of root
cause.
What actually changed (producer/run-daily-brief.sh, producer/.env):
- Stopped exporting
CLAUDE_CODE_OAUTH_TOKENat all -- it was unverified as necessary
(default Keychain-stored claude.ai session works fine headless, confirmed above) and
had silently rotted to blank without anyone noticing, which is its own lesson: an
unmonitored credential is worse than no credential.
- Added
check_auth_health(): a preflight that round-trips a real connector call
(M365 get_me, not a bare "reply OK" -- confirmed a bare call reports
is_error:false even when a connector is genuinely unreachable) before the main run,
retrying 3x/20s to absorb cold-start noise. On failure it SMS + notifies Tim
immediately and skips the run, instead of silently producing a connector-free brief
for days. This is the durable part of the fix: it doesn't prevent a recurrence, but
it makes a recurrence loud and same-morning instead of silent and multi-day.