WORKSPACE_MCP_STATELESS_MODE=true was already read, validated, and used to
configure the OAuth layer — but was never passed to server.run(). FastMCP
therefore always ran in stateful mode, keeping session state in memory.
On pod/process restart all in-memory sessions are lost, causing clients to
receive {"code":-32600,"message":"Session not found"} on their next request.
Passes stateless_http=is_stateless_mode() to server.run() so FastMCP drops
session tracking when stateless mode is configured, matching what the env var
already advertises.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When credentials had a refresh_token but credentials.expired was False
(e.g., token=None with no stored expiry), the refresh was skipped and
the server would start a new OAuth flow instead. This changes the
condition to attempt refresh whenever credentials are not valid and a
refresh_token is available, regardless of the expired flag.
Exposes native Google Docs createParagraphBullets and
deleteParagraphBullets APIs via the batch operation manager.
Supports UNORDERED (bullets), ORDERED (numbered), and NONE
(remove formatting) list types with optional nesting levels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows setting TITLE and SUBTITLE paragraph styles directly, in addition
to the existing heading_level (0-6) parameter. The new named_style_type
parameter accepts all Google Docs named styles: NORMAL_TEXT, TITLE,
SUBTITLE, HEADING_1 through HEADING_6.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When an HttpError occurs in Google Tasks tools, the error handler now checks
the HTTP status code before suggesting re-authentication. Re-auth messages are
only shown for 401 (Unauthorized) and 403 (Forbidden) errors.
This prevents misleading re-authentication suggestions for non-auth errors like
400 (Bad Request) with malformed arguments, allowing the LLM to focus on the
actual root cause instead of being misdirected by incorrect auth guidance.
The fix applies to both CLI mode (stdio legacy oauth) and MCP mode (OAuth 2.1).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Addresses CodeRabbit Review 4 nitpick: the test validates
parse_permissions_arg() so it belongs with that test class.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses CodeRabbit Review 3 nitpick: verify TASKS_READONLY_SCOPE is
present at full level, confirming cumulative scope expansion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add docstrings to test methods for coverage threshold
- Add autouse fixture to reset permission state between tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses CodeRabbit review — clear_completed is destructive and should
be blocked alongside delete at the manage permission level.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The consolidated manage_task tool bundles create/update/delete/move into a
single tool, making it impossible to deny just the delete action via tool
tiers or scope-based filtering.
This adds:
- A `manage` permission level for tasks (between readonly and full)
- A SERVICE_DENIED_ACTIONS registry mapping (service, level) to denied actions
- An is_action_denied() helper that tools call before executing actions
- Guards in manage_task and manage_task_list that reject denied actions
Usage: --permissions tasks:manage
Allows create, update, move. Denies delete.
tasks:full remains unchanged (all actions allowed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>