-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Context
We've been building an MCP server on top of gws (google-workspace-mcp) and wanted to share some patterns that solve problems we see recurring in the issue tracker. This isn't a feature request — it's a "here's what works" note in case it's useful upstream.
Problems we see users hitting
- Multi-account removed in v0.7 (Please restore multiple accounts being able to be used #439) — users need per-account credential routing for agent workflows
- Encrypted credentials fail but exported plaintext works (Encrypted credentials fail to authenticate; exported plaintext credentials work #515) — credential store reliability
- Agent safety (Feature request: Gmail draft-only mode for CLI+agent workflows #424, Add built in HITL that the agents can't edit in code #158) — users want draft-only mode, no-delete policies, HITL gates
- Raw API responses aren't agent-friendly (Feature request: Gmail +read helper for extracting message body as plain text #438) — agents need formatted, token-efficient output
- Scope gaps (Auth login missing scopes for People and Meet APIs #556) — auth login doesn't cover all supported services
Pattern: middleware layer on gws
We solved these by treating gws as an API engine and wrapping it with a thin middleware:
Multi-account via credential file routing
Account registry → per-account credential files → GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE env var
gws already supports GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE — we just maintain a registry of accounts and route each API call to the right credential file. No gws changes needed. This pattern could be documented as a recommended approach for multi-account setups.
Safety policies as composable beforeExecute hooks
// Configure via env var: GWS_SAFETY_POLICY="draft-only-email,no-delete,audit"
// Policy runs BEFORE gws is spawned — blocked operations never execute
evaluatePolicies(args, context, service)
→ 'allow' — proceed normally
→ 'block' — return explanation to agent, never call gws
→ 'audit' — log to stderr, proceedFour built-in policies:
- draft-only-email — blocks send/reply/forward, allows read/search/triage
- no-delete — blocks permanent deletion (trash is allowed)
- read-only — blocks all write operations
- audit — logs destructive operations to stderr
These compose: draft-only-email,no-delete,audit gives "read everything, log attempts, block sends and deletes."
This addresses #424 (draft-only mode) and #158 (HITL gates) without any gws changes — the policy layer sits between the agent and gws.
Agent self-discovery via capabilities endpoint
// Agent calls: manage_accounts { "operation": "capabilities" }
// Response:
{
"services": 6,
"operations": 51,
"safety_policies": ["draft-only-email", "no-delete"],
"summary": "You can read email and search files, but cannot send email or permanently delete anything."
}The agent knows its constraints before attempting operations — no wasted calls against blocked policies.
Manifest-driven tool generation from gws discovery
# manifest.yaml — one entry per operation, factory generates MCP tools
gmail:
operations:
search:
resource: users.messages.list
params:
query: { maps_to: q }
maxResults: { default: 10, max: 50 }
defaults:
userId: meWe use gws schema <service.resource.method> to discover parameters, then curate the manifest with agent-friendly descriptions and defaults. Adding a new operation is a YAML entry, not code.
What this suggests for gws
These patterns work as external middleware, but some would be more powerful if built into gws:
- Document the credential file routing pattern for multi-account — it works today, users just don't know about it
- Consider a policy/filter flag — something like
gws --policy draft-onlythat blocks send operations at the CLI level, before the API call. This would make agent safety a first-class gws feature - Structured output mode —
gws --format agentthat returns token-efficient markdown instead of raw JSON, similar to what our formatting facade does - Scope completeness — the auth login scope selector should cover all services gws supports (Auth login missing scopes for People and Meet APIs #556)
Evidence
- 51 operations across 6 services (gmail, calendar, drive, sheets, docs, tasks)
- Live tested: full email round trip (send, search, read, reply) across two accounts
- Safety policies tested: send blocked, delete blocked, search allowed, trash allowed
- 268 unit tests passing
- Published as mcpb with per-platform gws binaries bundled
The repo is at https://github.com/aaronsb/google-workspace-mcp if anyone wants to look at the implementation.