[BUG] Cloud routines / Claude Code on the web have no non-interactive way to trust a project-scoped `.mcp.json` MCP server - daily routine broke after the untrusted-workspace gate
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 happened
A scheduled Routine running on Claude Code on the web (cloud sandbox) calls tools from a project-scoped MCP server declared in the repo's .mcp.json, auto-approved via the repo's committed .claude/settings.json (permissions.allow: ["mcp__<server>__*"]).
This worked until ~2.1.196. Now every run, the MCP server sits at ⏸ Pending approval and/or its tools are denied, because the committed project config is treated as an untrusted workspace and ignored:
Ignoring N permissions.allow entries from .claude/settings.json: this workspace has not been trusted.
Run Claude Code interactively here once and accept the trust dialog, or set
projects["/path/to/repo"].hasTrustDialogAccepted: true in ~/.claude.json.
The relevant hardening:
2.1.196 — Security:claude mcp list/getno longer spawn.mcp.jsonservers that a repo self-approved via a committed.claude/settings.json; untrusted workspaces show⏸ Pending approval
(The project-scoped ⏸ Pending approval gate itself landed earlier, ~2.1.154.)
Why this is unfixable for a routine
Every documented remedy is interactive, and a cloud routine has no human and no TUI:
- "Accept the workspace trust dialog" — no dialog in a non-interactive cloud routine.
- "Approve the server in the
/mcppanel" — no/mcppanel in a routine. claude mcp reset-project-choices— interactive re-prompt; nothing to re-prompt to.hasTrustDialogAccepted: truein~/.claude.json— the cloud sandbox is re-cloned per run; there is no persistent~/.claude.jsonto set.
There is also no web-UI affordance to trust/approve a repo-scoped (.mcp.json) server — the connector UI only manages account-level connectors, so a server that exists only in the repo has nowhere to be approved from.
Net: the project-MCP approval model assumes an interactive session, but routines are non-interactive by definition. The two are mutually exclusive, with no escape hatch.
Repro
- Repo with
.mcp.jsondeclaring a project-scoped (e.g. HTTP) MCP server and.claude/settings.jsonwithpermissions.allow: ["mcp__<server>__*"]. - Configure a Routine on Claude Code web that calls a tool from that server.
- Run it (or wait for schedule).
- Server shows
⏸ Pending approval/ tool calls are denied; routine fails. No way to approve from within the non-interactive run.
Confirming the rule syntax is NOT the problem
The same glob, supplied from a trusted source (CLI flag, which bypasses the untrusted-workspace gate), auto-approves with zero denials — proving the permission rule is valid and the issue is purely trust-source, not syntax:
claude -p "call <tool>" --permission-mode default --allowedTools 'mcp__<server>__*'
→ result returned, permission_denials: []
Whereas relying on the committed permissions.allow from .claude/settings.json in the same (untrusted) workspace → ignored.
Expected
A non-interactive way for a cloud routine / web session to trust a project-scoped .mcp.json server + its tools, e.g. any of:
- A per-routine "trust this repo's MCP servers / approve these tools" setting in the web UI.
- Honor
enabledMcpjsonServers+permissions.allowfrom a committed.claude/settings.jsonwhen the routine owner is the repo owner (or behind an explicit opt-in flag). - A documented, supported headless approval (e.g.
claude mcp approve <server> --scope projectusable from a setup script).
Current workaround (for others hitting this)
Register the server from a trusted source the gate doesn't touch — user scope — at session start, e.g. in the cloud environment setup script (runs before the session) or a committed SessionStart hook:
claude mcp add -s user -t http <server> <url> -H "Authorization: Bearer $TOKEN"
with the secret in a cloud environment variable. Pair with a non-prompting permission mode. This sidesteps the repo-self-approval gate but defeats the point of repo-scoped config.
Related
- #69960 — Cloud routines (CCR) cannot use Slack MCP write tools, "Always allow" unavailable (closed, same class, routine case unsolved)
- #69055 — Routine inside Claude Code being skipped
- #9189 — Project-scoped MCP servers don't trigger approval prompt
- #63308 — docs omit
claude mcp list/getpending-approval output for unapproved project servers - #12227 — Workspace trust not persisting
- #67319 — Trust dialog never fires on a non-CLI surface → project
.claude/settings.jsonsilently skipped - #69953 — 3P mode: custom MCP servers blocked,
allowedMcpServershardcoded empty
Environment
- Claude Code 2.1.196
- Surface: Claude Code on the web (cloud routine / scheduled session)
- MCP: project-scoped HTTP server in
.mcp.json, bearer-auth
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗