Skip to content

Suggestion: middleware pattern for multi-account, agent safety, and formatted responses #558

@aaronsb

Description

@aaronsb

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

  1. 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
  2. Encrypted credentials fail but exported plaintext works (Encrypted credentials fail to authenticate; exported plaintext credentials work #515) — credential store reliability
  3. 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
  4. 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
  5. 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, proceed

Four 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: me

We 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:

  1. Document the credential file routing pattern for multi-account — it works today, users just don't know about it
  2. Consider a policy/filter flag — something like gws --policy draft-only that blocks send operations at the CLI level, before the API call. This would make agent safety a first-class gws feature
  3. Structured output modegws --format agent that returns token-efficient markdown instead of raw JSON, similar to what our formatting facade does
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions