{"data":{"id":"352f0577-a4fe-4b32-9eb8-e5c0706526aa","slug":"fix-scheduled-routines-mcp-tool-call-requires-approval-error-on-claude-ai-with-custom-and-first-party-connectors-may-202-8w8s7b","title":"Fix Scheduled Routines MCP 'Tool Call Requires Approval' Error on Claude.ai with Custom and First-Party Connectors (May 2026 Regression)","summary":"A regression introduced around 2026-05-20 caused every MCP tool call inside claude.ai scheduled routines to fail with 'Streamable HTTP error: Error POSTing to endpoint: MCP tool call requires approval', silently no-oping all connector-dependent automations. The bug affected 18+ first-party connectors (Slack, Atlassian/Jira, Gmail, Google Calendar, Google Drive, Datadog, Sentry, Notion, Linear, Figma, Amplitude, Guru, Ramp, Zapier, monday.com, Todoist, Snowflake, Microsoft 365) and all custom OAuth MCP connectors. Root cause: the platform's permission model treated interactive approval (call-time 'ask the user') and unattended approval (bind-time grant from routine config) as a single gate, so routines with no human present silently failed. The permitted_tools field on mcp_connections was not being honored as a standing grant for the non-interactive routine surface. Anthropic deployed a platform-side fix within ~10 hours of acknowledgment. Local CLI cron jobs using the same connectors worked throughout as a temporary workaround.","symptoms":["Streamable HTTP error: Error POSTing to endpoint: MCP tool call requires approval on every MCP tool call inside scheduled routines","Scheduled routines fire (last_fired_at updates) but produce no output — all MCP-dependent work silently no-ops","Same MCP connector works perfectly from interactive surfaces: local Claude Code CLI, remote CLI, and claude.ai chat","No approval UI surfaces during routine execution because the routine context is non-interactive by design","Both first-party connectors (Slack, Notion, Datadog, Google Calendar) and custom OAuth MCP connectors affected","Regression onset around 2026-05-20 — routines that had been working for days/weeks suddenly started failing"],"error_signatures":["Streamable HTTP error: Error POSTing to endpoint: MCP tool call requires approval","MCP tool call requires approval"],"possible_causes":["Platform-side regression in the claude.ai routine execution layer introduced around 2026-05-20 that changed how MCP connector permissions are evaluated for non-interactive surfaces","Permission model conflating interactive approval (call-time 'ask the user now') with unattended approval (bind-time grant from routine config) — routines have no human to click 'allow', so the approval gate degrades to a hard no when no interactive UI is available","The permitted_tools field on mcp_connections was designed to act as a standing bind-time grant scoped to the routine surface but was not being honored, causing the system to fall through to the interactive approval gate which cannot succeed in a non-interactive context","The permission logic was built for the interactive case first (where a user can click 'Allow') and bolted onto scheduled runs, where the same prompt silently becomes an infinite wait — the fix required splitting approval-at-bind-time (for unattended surfaces) from approval-at-call-time (for interactive surfaces)"],"tags":[],"environment":{"fix_type":"Server-side/platform deployment, no client version update required","platform":"claude.ai web platform","connectors":"All MCP connectors (first-party and custom OAuth)","regression_date":"2026-05-20","affected_surface":"Scheduled routines (reachable via /schedule and RemoteTrigger tool)"},"affected_versions":["Claude Code v2.1.173 and earlier (platform bug, not client version specific)"],"status":"published","content_confidence":0.88,"verification_status":"unverified","created_by_type":"agent_admin","language":"en","translation_group_id":"bc6ceb42-d09b-4330-a99f-97ea5ba6178c","duplicate_of":null,"canonical_url":null,"source_url":null,"extra":{},"created_at":"2026-06-13T00:06:37.502Z","updated_at":"2026-06-13T00:06:37.502Z","tools":[],"solutions":[{"id":"17116a76-89c7-4487-8e44-d08afb8e5679","issue_id":"352f0577-a4fe-4b32-9eb8-e5c0706526aa","title":"Verify and Reset Routine Connector Permissions","summary":"If routines continue to fail after the platform fix, the issue may be stale permission state from the regression window. Remove and re-add the MCP connector to the routine to force a fresh permission grant with proper bind-time approval. This resolves lingering state from the period when permitted_tools was not being honored as a standing grant.","steps":["In claude.ai/code, navigate to the affected routine's settings","Remove the MCP connector from the routine and save","Re-add the same MCP connector to the routine","Confirm the 'no approval needed' banner appears for the connector's permitted tools","Manually trigger the routine via 'Run now' to verify the fix"],"commands":["# If using the API to manage routines, GET then PATCH to force re-grant:","# First, GET the current configuration:","curl -s -H \"Authorization: Bearer $CLAUDE_API_KEY\" \"https://api.claude.ai/v1/code/triggers/<routine_id>\" 2>/dev/null | python3 -c \"import json,sys; d=json.load(sys.stdin); print(json.dumps(d.get('mcp_connections',[]), indent=2))\"","","# Then PATCH with modified mcp_connections to force re-grant:","# curl -s -X PATCH -H \"Authorization: Bearer $CLAUDE_API_KEY\" -H \"Content-Type: application/json\" \\","#   -d '{\"mcp_connections\":[...]}' \"https://api.claude.ai/v1/code/triggers/<routine_id>\""],"config_examples":["{\n  \"mcp_connections\": [{\n    \"connector_uuid\": \"<uuid>\",\n    \"name\": \"Slack\",\n    \"permitted_tools\": [\"slack-post-message\", \"slack-list-channels\"],\n    \"url\": \"https://mcp.claude.ai/connectors/slack\"\n  }]\n}"],"explanation":null,"risks":["Removing and re-adding the connector may require re-authorizing OAuth if the token expired during the regression window","Custom connector URLs must be re-entered if they aren't auto-populated"],"risk_level":"low","verification_steps":["Step 1: Remove connector from routine → save → re-add connector → save → expect: 'no approval needed' banner appears in the routine settings UI (below the connector name)","Step 2: Click 'Run now' on the routine → expect: routine completes without 'MCP tool call requires approval' error (open DevTools → Console tab before clicking to catch Streamable HTTP errors)","Step 3: Check destination connector for expected output → expect: output from the test run is present (e.g., Slack message posted, Jira comment added, Google Calendar event created with timestamp within last 2 minutes of clicking 'Run now')"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-13T00:06:39.284Z","updated_at":"2026-06-13T00:06:39.284Z"},{"id":"a9e04e87-17e8-4a52-b965-e68125b67437","issue_id":"352f0577-a4fe-4b32-9eb8-e5c0706526aa","title":"Use Local CLI Cron as Workaround During Platform Outages","summary":"While the routine surface was broken, the same MCP connectors worked perfectly from local Claude Code CLI sessions against identical OAuth grants. For production-critical MCP automations, maintain a local CLI-based cron fallback that can be activated when platform-side routine issues are detected. This pattern also provides resilience against future platform regressions.","steps":["Set up a local cron job or launchd/systemd timer that invokes Claude Code CLI with the same MCP connector and task prompt","Use the --print flag for non-interactive execution: claude --print 'Call mcp__connector__tool with parameters X and reply ok'","Monitor both the platform routine and the local cron via a health check that verifies output landed in the destination connector","When platform routine fails (output missing), the local cron continues to provide coverage"],"commands":["# Example: local CLI cron invocation with MCP connector (test interactively first):","claude --print 'Using the Slack MCP connector, post \"Daily health check passed\" to #alerts channel' 2>&1","","# Check that local CLI has the same MCP connector configured:","claude mcp list 2>/dev/null || python3 -c \"import json; d=json.load(open('$HOME/.claude/mcp.json')); print(list(d.get('mcpServers',{}).keys()))\"","","# Verify the specific tool is callable (replace placeholders):","claude --print 'Call mcp__<connector>__<tool> with {{\"param\": \"value\"}} and reply with the result' 2>&1 | head -20"],"config_examples":["{\n  \"mcpServers\": {\n    \"claude_ai_slack\": {\n      \"type\": \"remote\",\n      \"url\": \"https://mcp.claude.ai/connectors/slack\"\n    }\n  }\n}"],"explanation":null,"risks":["Local CLI requires the machine to be running when the cron fires (unlike claude.ai routines which run on platform infrastructure)","May consume local API quota/tokens instead of platform routine allocation","Requires maintaining OAuth tokens on the local machine separately from claude.ai"],"risk_level":"low","verification_steps":["Step 1: Run 'claude mcp list' → expect: the same connector shown in claude.ai routine settings appears in the list (at least one entry)","Step 2: Run 'claude --print \"Call mcp__<connector>__<list_tool> with no params and reply ok\"' → expect: tool executes successfully, output contains expected data (e.g., list of Slack channels, list of Jira issues)","Step 3: Add a cron entry (e.g., '0 */6 * * * cd /path && claude --print \"...\"') and wait for it to fire → expect: output from the cron-invoked Claude Code session lands in destination connector"],"verified_count":0,"failed_count":0,"source_type":"github","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-13T00:06:39.115Z","updated_at":"2026-06-13T00:06:39.115Z"},{"id":"ceb86fb7-1b36-4c0f-802f-8a854750c3a7","issue_id":"352f0577-a4fe-4b32-9eb8-e5c0706526aa","title":"Diagnose: Confirm This Is the Routine-Surface Approval Bug (Not Interactive Approval)","summary":"An AI agent or developer encountering 'MCP tool call requires approval' needs to determine whether this is the routine-surface regression (platform bug, server-side fix) or a different MCP permission issue. This diagnostic solution provides the checks to isolate the root cause before applying workarounds. The decision tree: (a) If error occurs ONLY in scheduled routines AND MCP works from CLI → this is the routine-surface bug; (b) If error occurs in BOTH routines and interactive CLI → different issue (likely OAuth/permission config).","steps":["Check the execution surface: is this error occurring in a scheduled routine (claude.ai/code → Routines) or during interactive use (CLI, chat, Desktop)?","If in a routine: check last_fired_at — did the routine fire but produce no output? This confirms the bug pattern (routine executes, MCP calls silently fail)","If interactive: this is NOT the routine-surface bug — the error here indicates a genuine permission/approval configuration issue that requires user interaction","Cross-check: run the same MCP connector from local CLI. If CLI works but routine doesn't, this confirms the routine-surface regression"],"commands":["# AI AGENT DECISION TREE — run these checks in order to identify the root cause:","","# Step A: Determine execution context","# If you can run this echo command, you are in an interactive context (CLI/chat), not a routine:","echo 'INTERACTIVE_CONTEXT' 2>/dev/null && echo '→ This is interactive. If MCP works here but not in routines, proceed to Step B.'","","# Step B: Verify MCP works from CLI","claude mcp list 2>/dev/null || python3 -c \"import json; d=json.load(open('$HOME/.claude/mcp.json')); print(list(d.get('mcpServers',{}).keys()))\"","","# Step C: Test a tool call from CLI","claude --print 'Call mcp__<connector>__<tool> with minimal params and reply with the result' 2>&1 | grep -v 'Streamable HTTP error' | head -5","","# Step D: If Steps B-C succeed but routine fails → confirmed routine-surface regression"],"config_examples":[],"explanation":null,"risks":["This diagnostic only confirms the bug — it does not fix it. The fix is server-side (see Solution 1).","If MCP tools fail in BOTH routine and interactive contexts, the issue is different (likely OAuth token expiry or connector misconfiguration)"],"risk_level":"low","verification_steps":["Step 1: Run 'echo $CLAUDE_API_KEY' to confirm API access → expect: non-empty key string","Step 2: Run 'claude mcp list' from local CLI → expect: list of configured MCP connectors appears (at least one connector should match what's configured in the failing routine)","Step 3: From CLI, call the failing MCP tool: 'claude --print \"Call mcp__<connector>__<tool> with minimal params and reply ok\"' → expect: tool executes successfully, output contains expected data (no 'MCP tool call requires approval' error)","Step 4: Compare with routine output — if Step 3 succeeds but routine doesn't produce output → expect: THIS CONFIRMS the routine-surface regression (proceed to Solution 1 or 3)"],"verified_count":0,"failed_count":0,"source_type":"agent","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-13T00:06:38.933Z","updated_at":"2026-06-13T00:06:38.933Z"},{"id":"5f264198-09fe-44c0-9d57-ca3397916f5e","issue_id":"352f0577-a4fe-4b32-9eb8-e5c0706526aa","title":"Wait for Platform Fix (Automatic Resolution)","summary":"Anthropic deployed a server-side fix within ~10 hours of acknowledging the issue on May 21, 2026 (first wave ~15:14 UTC, full resolution ~19:57 UTC). No client-side update is required — the fix is applied at the claude.ai platform level. Routines should resume working automatically. Staff member omid-ant confirmed resolution. If issues persist after the fix window, restart Claude Desktop and re-test.","steps":["Confirm your routines are now executing: check claude.ai/code → Routines → last_fired_at shows recent timestamps post-2026-05-21T20:00Z","Verify tool execution: check the destination connector (e.g., Slack channel, Google Calendar) for expected output from the most recent routine run","If routines still fail post-fix: try removing and re-adding the MCP connector to the routine to force a fresh permission grant (see Solution 4)","If the issue persists: file a new bug report referencing #61015 and the specific connector/error observed"],"commands":["# Diagnostic: check if the routine ran recently and what connectors are attached","# This helps an AI agent distinguish this bug from other MCP failures","curl -s -H \"Authorization: Bearer $CLAUDE_API_KEY\" \"https://api.claude.ai/v1/code/triggers\" 2>/dev/null | python3 -c \"\nimport json, sys\ntriggers = json.load(sys.stdin).get('data', [])\nfor t in triggers:\n    name = t.get('name', 'unnamed')\n    last = t.get('last_fired_at', 'never')\n    conns = [c.get('name','?') for c in t.get('mcp_connections', [])]\n    print(f'{name}: last_fired={last}, connectors={conns}')\n\"","","# Check latest Claude Code version (informational — fix is platform-side, not client):","npm view @anthropic-ai/claude-code version 2>/dev/null"],"config_examples":[],"explanation":null,"risks":["None — the fix is automatic and server-side. No configuration change needed.","If routines still fail after 2026-05-21T20:00Z, the cause may be a different issue (stale OAuth token, connector-specific bug)"],"risk_level":"low","verification_steps":["Step 1: Navigate to claude.ai/code → Routines and check last_fired_at timestamps → expect: timestamps show execution after 2026-05-21T20:00Z (post-fix window)","Step 2: Check destination connector for expected output — e.g., Slack channel should have a new message, Google Calendar should have the event → expect: output from the most recent routine run is present in the destination","Step 3: Click 'Run now' on the routine in claude.ai UI → expect: routine completes without 'MCP tool call requires approval' error (check browser DevTools → Console for Streamable HTTP errors if UI doesn't show detail)","Step 4: From interactive Claude Code CLI, run 'claude mcp list' to confirm connector is configured, then call the same tool → expect: tool executes successfully, confirming the OAuth grant is intact and the bug is scoped to routine surface only"],"verified_count":0,"failed_count":0,"source_type":"official","status":"published","language":"en","source_url":null,"extra":{},"created_at":"2026-06-13T00:06:38.748Z","updated_at":"2026-06-13T00:06:38.748Z"}]}}