Gmail MCP connector: write operations (label_thread/archive/trash) fail in remote routines due to JIT scope upscoping

Resolved 💬 4 comments Opened May 12, 2026 by jasonjgarcia24 Closed May 12, 2026

Summary

The Gmail MCP connector works correctly in interactive Claude Code sessions (reads + writes both succeed) but write operations fail in remote routines (scheduled remote agents at claude.ai/code/routines). The failure mode is consistent and reproducible: all label_thread, unlabel_thread, archive, and trash calls return HTTP 403 with the message "Server returned 403 after trying upscoping" (sometimes also surfaced as "MCP server 'Gmail' requires re-authorization (token expired)").

Read operations (search_threads, get_thread, list_labels) succeed in the same routine session that fails writes — so this is not a token-expiry issue. It appears to be a scope-grant issue: the Gmail MCP requests the gmail.modify scope just-in-time via OAuth upscoping when a write is first attempted, which works in interactive sessions (the user clicks "Allow") but cannot succeed in a routine (no interactive consent surface).

Environment

  • Claude Code via claude.ai → Routines / Remote Agents
  • Routine environment: Default Cloud Environment (env_01V1ByqnE16J3rWFMAHE9i1E, kind: anthropic_cloud)
  • Affected connector: Gmail (connector_uuid: 5f9f3a8d-2a2f-4ce6-a3e2-29afc2083329)
  • Model: claude-sonnet-4-6
  • Reproduced: 2026-05-11 and 2026-05-12 across multiple routine runs

Expected behavior

A routine that has the Gmail MCP attached should be able to call label_thread, archive, etc. successfully on the user's behalf, using scopes granted at connector-attachment time.

Actual behavior

Every write operation returns:

Server returned 403 after trying upscoping

…and the digest produced by the routine notes Auto-handled: 0 with all writes blocked. Reads work fine.

Steps to reproduce

  1. Connect Gmail at claude.ai/customize/connectors (verify modify scope grant).
  2. In an interactive Claude Code session, confirm label_thread works (it does).
  3. Create a remote routine with Gmail attached as an MCP connection.
  4. Have the routine call mcp__claude_ai_Gmail__label_thread on any thread.
  5. Observe the 403 in the routine run log.

What I've tried (none fixed it)

  • Reconnecting the Gmail connector (multiple times, including full revoke at https://myaccount.google.com/permissions → reconnect with all scope checkboxes selected)
  • Clearing and re-adding mcp_connections on the existing routine via the routines API
  • Creating a brand-new routine with identical config (test ID trig_01En28ij99f9iNQzGwSwb4as, since disabled) — same 403, confirming the bug is environment-level, not per-routine-state

Diagnostic evidence

  • Same OAuth identity (jason.garcia24@gmail.com), same connector_uuid, same Gmail tools available in both surfaces.
  • Reads succeed in the routine session that fails writes — rules out token expiry.
  • Local interactive Claude Code can write to Gmail concurrent with the routine failing to write.

Suggested fix

Make the Gmail connector grant gmail.modify (and other write scopes) at connector-attachment time, with full user consent up front — so routines can use these scopes without needing to upscope mid-session.

Workaround

Treat routines as classify+propose+report only. Have a separate interactive surface (Claude-in-Slack, local Claude Code) perform the actual Gmail writes when the user gives the go-ahead. The routine produces the digest with proposed actions; the interactive agent applies them.

Affected routine ID for support context: trig_01M36Z1teyGC5zWkDPbopK8C (account febd00f1-c857-453f-b3cf-abdfffe64188).

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗