# https://github.com/taylorwilsdon/google_workspace_mcp Project Manual

Generated at: 2026-06-04 17:00:30 UTC

## Table of Contents

- [Overview & System Architecture](#page-1)
- [Authentication, OAuth 2.1, Security & Credential Storage](#page-2)
- [Service Modules, Tool Tiers & Granular Permissions](#page-3)
- [Deployment, CLI, Storage Backends & Operations](#page-4)

<a id='page-1'></a>

## Overview & System Architecture

### Related Pages

Related topics: [Authentication, OAuth 2.1, Security & Credential Storage](#page-2), [Service Modules, Tool Tiers & Granular Permissions](#page-3), [Deployment, CLI, Storage Backends & Operations](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)
- [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py)
- [core/tool_tiers.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tiers.yaml)
- [core/comments.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/comments.py)
- [core/__init__.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/__init__.py)
- [core/log_formatter.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/log_formatter.py)
- [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py)
- [core/api_enablement.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/api_enablement.py)
- [core/utils.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/utils.py)
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md)
- [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py)
</details>

# Overview & System Architecture

The **Google Workspace MCP Server** is a Model Context Protocol (MCP) integration that exposes Google Workspace services (Gmail, Calendar, Drive, Docs, Sheets, Slides, Forms, Tasks, Chat, and Apps Script) to AI agents. It enables AI clients to author, manage, and execute automations across the entire Workspace ecosystem through a unified, tier-gated tool surface backed by Google OAuth and the official Google APIs.

## Purpose and Scope

The server's primary role is to bridge natural-language AI agents and Google Workspace APIs. As described in [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md), the integration provides "17 tools across core and extended tiers for complete Apps Script lifecycle management," letting agents do everything from listing projects to deploying versioned automations. The same tiered, lifecycle-oriented design is applied uniformly across all supported Workspace services.

The system's goals are to:

- Provide **cross-application automation** beyond the scope of any single Workspace API.
- Offer **persistent, hostable logic** through Apps Script while remaining MCP-native.
- Expose **read-only and destructive operations** under separate, auditable tool tiers.
- Support deployment in both **local** and **containerized (Kubernetes/Helm)** environments.

The server deliberately does not replace the Google Apps Script editor UI, does not run arbitrary JavaScript outside script-defined functions, and does not provide IDE features such as autocomplete ([gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)).

## Core Architectural Components

The architecture is composed of several cooperating modules under the `core/` package and the `auth/` package referenced in [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

### FastMCP Server and Authentication

[core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py) instantiates a `FastMCP` server, registers Google OAuth 2.1 providers (`GoogleProvider`), and installs middleware such as `AuthInfoMiddleware` and `MCPSessionMiddleware`. It also routes legacy OAuth callbacks via `handle_auth_callback` and `start_auth_flow`, and supports transport-mode switching (`stdio`, `http`) through `core.config`.

### Tool Tier System

A defining architectural pattern is the **three-tier tool model** — `core`, `extended`, and `complete` — declared in [core/tool_tiers.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tiers.yaml). The loader in [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py) defines `TierLevel = Literal["core", "extended", "complete"]` and parses the YAML into a per-service tool allow-list. For example, the `gappsscript` service exposes core tools like `list_script_projects`, `run_script_function`, and `generate_trigger_code`, and extended tools like `manage_deployment` and `list_deployments`.

The registry in [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py) provides a `conditional_tool(server, tool_name)` decorator that decorates a function with `@server.tool()` only if that tool is enabled in the current tier set. This allows every tool implementation to remain unconditionally imported yet selectively registered at startup, supporting both lean "core-only" deployments and "complete" installations with the full toolset.

### Shared Utilities and Error Handling

[core/utils.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/utils.py) supplies PDF text extraction (`extract_pdf_text` via `pypdf`), Office XML parsing, and image base64 encoding. Its `handle_http_errors` decorator converts raw `HttpError` exceptions into user-actionable messages, branching on 401/403 to suggest re-authentication flows and on `403 PERMISSION_DENIED` to trigger the API enablement helper.

[core/api_enablement.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/api_enablement.py) parses error details to extract the API service name and project ID, then generates a direct Google Cloud Console link so the user can enable the missing API. Internal aliases (e.g., `calendar` → `calendar-json.googleapis.com`) and display names are both resolved before a link is emitted.

### Cross-App Comment Subsystem

[core/comments.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/comments.py) centralizes comment handling for Docs, Sheets, and Slides via the Drive API. `_manage_comment_dispatch` routes `create`, `reply`, and `resolve` actions to per-app implementations, and `READ_COMMENT_ANNOTATIONS` / `MANAGE_COMMENT_ANNOTATIONS` use `ToolAnnotations` to declare read-only and destructive hints that MCP clients can honor.

### Logging and Diagnostics

[core/log_formatter.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/log_formatter.py) installs `setup_enhanced_logging` and rewrites high-frequency log lines — tier resolutions, configuration paths, and filter summaries — into compact, scannable strings such as `Tool tier 'core' loaded: 14 tools across 3 services [calendar, docs, sheets]`. This makes operator-facing startup logs readable in both console and structured-log pipelines.

## High-Level Data Flow

The end-to-end flow from an AI agent to a Google API call is intentionally simple and uniform across services.

```mermaid
flowchart LR
    A[AI Agent / MCP Client] -->|JSON-RPC tool call| B[FastMCP Server core/server.py]
    B --> C{Tool Tier Filter core/tool_registry.py}
    C -->|enabled| D[Service Tool Module e.g. gappsscript]
    C -->|disabled| X[Tool Not Advertised]
    D --> E[require_google_service auth/service_decorator]
    E --> F[Google API SDK]
    F --> G[handle_http_errors core/utils.py]
    G -->|on 403| H[API Enablement Helper core/api_enablement.py]
    G --> A
```

Every tool call passes through tier-based registration (so disabled tools are never advertised), Google service authentication, and centralized error handling. The `core/` package itself is initialized as a standard Python package by [core/__init__.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/__init__.py), which simply makes the directory importable.

## Deployment Topology

The project supports two deployment models described in [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md):

- **Local / developer mode** — direct process launch with OAuth credentials managed on disk.
- **Kubernetes via Helm** — containerized deployment requiring Kubernetes 1.19+ and Helm 3.2.0+, with `secrets.googleOAuth.clientId` and `secrets.googleOAuth.clientSecret` supplied at install time. Replica count, image repository/tag, and pull policy are configurable, allowing horizontal scaling and rolling updates.

In both topologies, the tier loader, tool registry, and shared utility layer behave identically; only the surrounding packaging changes.

## Design Trade-offs and Constraints

Several constraints are documented and should be respected by integrators. Per [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md):

- **No direct API-based trigger management** — the `generate_trigger_code` tool emits ready-to-use Apps Script that the user pastes into the editor.
- **Execution timeouts** — 30 seconds for simple/custom functions and 6 minutes for API-executed runs.
- **Function execution requires an API Executable deployment**, configured manually in the Apps Script editor.
- **Daily URL Fetch quotas** apply (e.g., 20,000/day for consumer accounts).

These trade-offs keep the server's blast radius small: it orchestrates Google APIs through well-understood mechanisms rather than attempting to replicate the Apps Script IDE.

## See Also

- [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md) — Apps Script tool reference and prerequisites.
- [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py) — Tool tier resolution logic.
- [core/tool_tiers.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tiers.yaml) — Canonical tier → tool allow-list.
- [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py) — Conditional tool registration.
- [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py) — Server bootstrap and middleware.
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md) — Kubernetes deployment reference.

---

<a id='page-2'></a>

## Authentication, OAuth 2.1, Security & Credential Storage

### Related Pages

Related topics: [Overview & System Architecture](#page-1), [Deployment, CLI, Storage Backends & Operations](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py)
- [core/config.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/config.py)
- [core/context.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/context.py)
- [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py)
- [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py)
- [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py)
- [core/comments.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/comments.py)
- [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md)
</details>

# Authentication, OAuth 2.1, Security & Credential Storage

## Overview and Purpose

The `google_workspace_mcp` server exposes Google Workspace capabilities to Model Context Protocol (MCP) clients. Because every tool call ultimately issues authenticated Google API requests, the project ships a dedicated authentication, OAuth, and credential-storage layer. The layer is designed to satisfy two distinct audiences:

- **Single-user / local developers** running the server on a workstation, where a desktop OAuth 2.0 flow is acceptable.
- **Multi-user / hosted deployments** (Kubernetes, remote MCP clients) that require the OAuth 2.1 protocol with bearer-token authentication, dynamic client registration (DCR), and protected-resource metadata.

Both audiences share the same on-disk credential store abstraction, the same scope configuration, and the same request-scoped context plumbing. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py), [core/config.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/config.py).

## Authentication Modes

### OAuth 2.1 (default, multi-user)

When `MCP_ENABLE_OAUTH21` is true (the Helm default), the server wires up `fastmcp`'s `GoogleProvider` and requires a `GOOGLE_OAUTH_CLIENT_ID` for the `streamable-http` transport. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py), [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md).

The provider is configured with:

- `required_scopes` and `valid_scopes` derived from `get_current_scopes()` and `PROTOCOL_AUTH_SCOPES`. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- A JWT signing key. If `FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY` is unset, the key is derived from the Google OAuth client secret via `derive_jwt_key(...)`. A warning is logged when the override is shorter than 12 characters. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- An allowlist of client redirect URIs read from `WORKSPACE_MCP_ALLOWED_CLIENT_REDIRECT_URIS`, plus DCR defaults that mirror the full set of valid scopes. CIMD (Client ID Metadata Document) clients also receive the full valid-scope string as their default scope. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

The legacy `start_google_auth` tool is explicitly disabled under OAuth 2.1, returning a guidance message that asks the client to complete the MCP-client OAuth flow (or supply a bearer token from an external OAuth 2.1 provider) before retrying. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

### Legacy OAuth 2.0 / Single-user mode

`singleUserMode` (Helm value) and the absence of `MCP_ENABLE_OAUTH21` fall back to the older desktop-OAuth flow. The Helm chart documents this as incompatible with OAuth 2.1 and recommends it only for trusted network paths. Source: [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md).

## Request-Scoped Context and Middleware

OAuth credentials and the FastMCP session ID are propagated through `contextvars`, not thread-locals, so they remain isolated per request and survive async fan-out. `set_injected_oauth_credentials(...)` is called by the service decorator; readers fetch them via `get_injected_oauth_credentials()`. Source: [core/context.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/context.py).

Two ASGI middlewares guard the HTTP surface:

- `OriginValidationMiddleware` — rejects browser-originated requests from origins that are neither loopback nor listed in `config.get_allowed_origins()` (or `WORKSPACE_EXTERNAL_URL`). It returns HTTP 403 with `{"error": "Origin not allowed"}`. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- `WellKnownCacheControlMiddleware` — forces `no-cache` headers on OAuth well-known discovery endpoints to prevent intermediaries from caching them. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

## Credential Storage and CLI Token Cache

The OAuth 2.1 proxy persists registered client registrations and tokens in one of three backends selected at runtime:

| Backend | Trigger | Notes |
|---|---|---|
| Memory (default) | `WORKSPACE_MCP_OAUTH_PROXY_STORAGE_BACKEND` unset | Ephemeral, suitable for dev |
| Disk | `WORKSPACE_MCP_OAUTH_PROXY_STORAGE_BACKEND=disk` | Persists across restarts |
| Valkey / Redis | `=valkey` or `WORKSPACE_MCP_OAUTH_PROXY_VALKEY_HOST` set | Uses `ValkeyStore` with TLS, port, and DB overrides |

Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

The companion CLI (`workspace-cli`) maintains a separate, long-lived token cache under `~/.workspace-mcp/cli-tokens`, encrypting payloads with a Fernet key stored at `~/.workspace-mcp/.cli-encryption-key` with `0o600` permissions. This avoids re-running the browser OAuth flow on every `fastmcp list/call` invocation. Source: [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py).

```mermaid
flowchart LR
    Client[MCP Client] -->|Bearer / OAuth 2.1| Origin[OriginValidationMiddleware]
    Origin --> Provider[GoogleProvider / DCR]
    Provider --> Store{Storage Backend}
    Store -->|memory| M[(In-process dict)]
    Store -->|disk| D[(Disk-backed store)]
    Store -->|valkey| V[(Valkey / Redis)]
    Provider --> JWTCheck[JWT signing key derive/validate]
    JWTCheck --> Tools[Workspace Tools]
    Tools --> Context[contextvars: injected creds + session]
    Context --> GoogleAPIs[Google Workspace APIs]
```

## Tool Gating, Scopes, and Read-Only Modes

The `conditional_tool` decorator consults a global enabled-set so that a server launched with `--tools gmail,calendar` only registers the requested tools. Source: [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py).

Three orthogonal toggles further restrict what registered tools can do:

- **Tier loader** — `core/tool_tier_loader.py` resolves tier names (`core`, `extended`, `complete`) against `core/tool_tiers.yaml` so deployments can opt in to advanced tools (e.g. Apps Script deployments) only when needed. Source: [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py).
- **Read-only mode** — when enabled, only scopes from `get_all_read_only_scopes()` are advertised; destructive tools are not registered. Source: [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py).
- **Permissions mode** — `get_allowed_scopes_set()` narrows the OAuth scope list exposed to the provider, which in turn constrains DCR-issued clients. Source: [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py).

For Apps Script specifically, the tier-bundled scope set includes `script.projects`, `script.deployments`, `script.processes`, `script.metrics`, `drive.file`, and others, all of which the provider advertises as valid and (where applicable) required. Source: [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md), [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).

## Security Considerations and Failure Modes

- **JWT key weakness** — operators that set `FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY` to a short string are warned at startup; the server still derives a key but recommends a longer secret. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- **Missing client configuration** — running `streamable-http` without `GOOGLE_OAUTH_CLIENT_ID` raises a `RuntimeError`, preventing an insecure boot. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- **Cross-origin attacks** — untrusted browser origins are blocked at the ASGI layer before any tool dispatch. Source: [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py).
- **Local file permissions** — CLI encryption keys are created with `O_EXCL` and `0o600`, mitigating credential theft from a shared host. Source: [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py).
- **Comment and content safety** — mutating tools (e.g. `MANAGE_COMMENT_ANNOTATIONS`) are explicitly marked non-idempotent so MCP clients and reviewers can apply stricter review policies. Source: [core/comments.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/comments.py).
- **Port drift** — `WORKSPACE_MCP_PORT` is resolved lazily through PEP 562 `__getattr__` so that `auth.port_resolver` changes applied after import are still observed by downstream consumers. Source: [core/config.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/config.py).

## See Also

- [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py) — OAuth 2.1 provider, ASGI middleware, storage backends
- [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py) — Persistent CLI with encrypted token cache
- [core/config.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/config.py) — Shared runtime configuration
- [core/context.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/context.py) — Request-scoped credential context
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md) — Kubernetes deployment and OAuth 2.1 setup

---

<a id='page-3'></a>

## Service Modules, Tool Tiers & Granular Permissions

### Related Pages

Related topics: [Overview & System Architecture](#page-1), [Authentication, OAuth 2.1, Security & Credential Storage](#page-2), [Deployment, CLI, Storage Backends & Operations](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py)
- [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py)
- [core/tool_tiers.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tiers.yaml)
- [core/utils.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/utils.py)
- [core/api_enablement.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/api_enablement.py)
- [core/comments.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/comments.py)
- [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py)
- [gappsscript/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md)
</details>

# Service Modules, Tool Tiers & Granular Permissions

## Overview

The `google_workspace_mcp` project exposes Google Workspace capabilities to Model Context Protocol (MCP) clients through a modular, tier-based architecture. Each Google service (Gmail, Drive, Calendar, Docs, Sheets, Chat, Forms, Apps Script, etc.) is implemented as an independent **service module** that registers a curated set of tools. To balance capability with safety, the project layers three orthogonal control mechanisms on top of the modules:

1. **Tool Tiers** — coarse-grained grouping (`core`, `extended`, `complete`) that bundles tools by complexity.
2. **Conditional Tool Registration** — a runtime gate that enables or hides individual tools based on configuration.
3. **Granular Permissions** — read-only mode, scope management, and OAuth 2.1 enforcement that restrict *what* authenticated callers can do.

Together they let an operator ship a minimal "core" toolset to end users while still being able to opt into advanced capabilities for trusted environments. Source: [core/tool_tier_loader.py:1-15]()

## Tool Tiers & YAML Configuration

The tier definitions live in a single YAML file: `core/tool_tiers.yaml`. Each top-level key is a service name; each service lists tools in `core`, `extended`, and `complete` buckets. For example, the Apps Script module declares seven core tools (`list_script_projects`, `get_script_project`, `get_script_content`, `create_script_project`, `update_script_content`, `run_script_function`, `generate_trigger_code`) and eight extended tools covering deployments, versions, and execution monitoring. Source: [core/tool_tiers.yaml:1-25]() and [gappsscript/README.md:55-78]()

The `ToolTierLoader` class resolves a tier into concrete tool and service lists. It loads the YAML once, caches the result, and exposes helpers like `get_tools_up_to_tier(tier, services)` and `get_services_for_tools(tools)`. Source: [core/tool_tier_loader.py:18-75]() The convenience helper `resolve_tools_from_tier(tier, services)` returns a `(tool_names, service_names)` tuple and logs a summary such as `Tier 'core' resolved to 7 tools across 1 services`. Source: [core/tool_tier_loader.py:85-110]()

```mermaid
flowchart LR
    A[tool_tiers.yaml] --> B[ToolTierLoader]
    B --> C{resolve_tools_from_tier}
    C -->|core| D[Minimal safe set]
    C -->|extended| D
    C -->|complete| D
    D --> E[Tool Registry]
    E --> F[FastMCP server.tool]
```

The `Literal["core", "extended", "complete"]` type alias makes the supported values explicit at every call site. Source: [core/tool_tier_loader.py:14]()

## Conditional Tool Registration

Rather than calling `server.tool()` directly, modules use a `conditional_tool` decorator. The decorator inspects a module-level `_enabled_tools` set; if the tool name is present, it forwards to the real FastMCP registration, otherwise it returns the function unchanged. Source: [core/tool_registry.py:35-55]()

The set is populated by the loader after the tier has been resolved. `set_enabled_tools()` and `is_tool_enabled()` form the public API of the registry. When the set is `None` (the default), every tool is enabled — preserving backward compatibility for deployments that do not opt into tiering. Source: [core/tool_registry.py:12-32]()

The Helm chart reinforces this by exposing `tools.enabled` as a configurable list, allowing operators to ship a hardened subset without editing code. Source: [helm-chart/workspace-mcp/README.md:18-22]()

## Granular Permissions

Beyond tiering, the project offers finer-grained controls that operate *after* a tool is registered:

- **Read-only mode** — `is_read_only_mode()` and `get_all_read_only_scopes()` from `auth.scopes` are imported by the registry so a tool can down-scope its OAuth requests when the operator has flipped the switch. Source: [core/tool_registry.py:6-10]()
- **Permissions mode** — `is_permissions_mode()` and `get_allowed_scopes_set()` from `auth.permissions` gate which OAuth scopes are honored. Source: [core/tool_registry.py:7-10]()
- **OAuth 2.1** — `is_oauth21_enabled()` lets the registry and error handlers choose the right re-auth hint. When an external provider supplies tokens, error messages ask the LLM to request a new bearer token; otherwise they point at the MCP client's OAuth flow. Source: [core/utils.py:1-15]() and [core/tool_registry.py:6]()

The `handle_http_errors` decorator centralizes API failure responses. On a `403` it inspects the error body for an API enablement link, generates a friendly message via `get_api_enablement_message`, and appends a re-auth hint appropriate for the active OAuth mode. Source: [core/utils.py:1-40]() and [core/api_enablement.py:1-30]()

## Shared Building Blocks

Service modules share infrastructure beyond tiering. `core/comments.py` exposes `READ_COMMENT_ANNOTATIONS` and `MANAGE_COMMENT_ANNOTATIONS` `ToolAnnotations` so every Docs/Sheets/Slides tool that touches comments declares the same idempotency and destructive hints. The `_manage_comment_dispatch` helper routes `create`/`reply`/`resolve` actions to a single Drive-API-backed implementation, eliminating duplication across service modules. Source: [core/comments.py:1-55]()

The `core/cli.py` module provides a `workspace-cli` entry point that connects to a running server, lists the available tools (filtered by the active tier), and invokes a single tool with `key=value` arguments. This makes it easy to smoke-test which tools a particular tier exposes without writing a full MCP client. Source: [core/cli.py:1-40]()

## Failure Modes & Common Pitfalls

- **Missing YAML** — `ToolTierLoader._load_config` raises `FileNotFoundError` if `tool_tiers.yaml` is absent. Operators must mount the file alongside the application. Source: [core/tool_tier_loader.py:30-50]()
- **Invalid YAML** — A `yaml.YAMLError` is rewrapped as `ValueError`, surfacing parser errors at startup rather than at first tool call. Source: [core/tool_tier_loader.py:45-55]()
- **Unknown tier** — The `Literal` type catches mistakes at static-analysis time; passing an unrecognised value at runtime will return whatever the YAML dictionary yields (often an empty list). Source: [core/tool_tier_loader.py:14]()
- **Tier mismatch with code** — A tool listed in code but absent from `tool_tiers.yaml` will not appear in any tier's resolved set; the registry's `is_tool_enabled` will return `False` for it. Source: [core/tool_registry.py:25-32]()
- **API not enabled** — `get_api_enablement_message` extracts the API service name and project ID from a `403` body and returns a deep link to the Google Cloud Console; without this helper users see only a generic `accessNotConfigured` error. Source: [core/api_enablement.py:1-35]()

## See Also

- Project README and setup guide in the repository root
- `gappsscript/README.md` for a worked example of tier usage in a single service module
- Helm chart values reference for production deployment settings

---

<a id='page-4'></a>

## Deployment, CLI, Storage Backends & Operations

### Related Pages

Related topics: [Overview & System Architecture](#page-1), [Authentication, OAuth 2.1, Security & Credential Storage](#page-2), [Service Modules, Tool Tiers & Granular Permissions](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [Dockerfile](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/Dockerfile)
- [docker-compose.yml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/docker-compose.yml)
- [.dockerignore](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/.dockerignore)
- [helm-chart/workspace-mcp/README.md](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md)
- [helm-chart/workspace-mcp/values.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/values.yaml)
- [helm-chart/workspace-mcp/templates/deployment.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/templates/deployment.yaml)
- [core/cli.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py)
- [core/server.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py)
- [core/tool_tier_loader.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py)
- [core/tool_tiers.yaml](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tiers.yaml)
- [core/tool_registry.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py)
- [core/utils.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/utils.py)
- [core/log_formatter.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/log_formatter.py)
- [core/api_enablement.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/api_enablement.py)
- [core/storage.py](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/storage.py)
</details>

# Deployment, CLI, Storage Backends & Operations

## Purpose and Scope

The Deployment, CLI, Storage Backends & Operations layer of `google_workspace_mcp` is the operational surface that takes the Model Context Protocol (MCP) server from source to a running, authenticated, and persistent service. It bundles four concerns: container packaging, orchestration manifests, the persistent command-line client, and runtime configuration of storage backends and tool tiers. Together they let administrators run the server locally, in Docker, in Kubernetes, or in distributed production environments, while letting operators cache OAuth tokens and selectively enable tool surfaces.

## Deployment Options

The repository supports three primary deployment paths.

**Python / `uv` (local development).** The simplest path is direct execution via the `uv` package manager. The `core/cli.py` module documents the typical invocation `uv run main.py --tools appscript` to start the server with a specific tool set, and `uv run workspace-cli list` to introspect a running server [Source: [gappsscript/README.md:1-100](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)].

**Docker / Docker Compose.** A multi-stage `Dockerfile` packages the application and its Python dependencies, while `docker-compose.yml` is provided for one-command local stack bring-up. `.dockerignore` keeps build context lean. This path is recommended for users who want an isolated runtime without managing a Python environment.

**Helm chart (Kubernetes).** The chart at `helm-chart/workspace-mcp/` requires Kubernetes 1.19+ and Helm 3.2.0+, and exposes a typed configuration surface for replica count, container image, pull policy, and Google OAuth credentials [Source: [helm-chart/workspace-mcp/README.md:1-40](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/helm-chart/workspace-mcp/README.md)]. A typical install injects secrets at the command line:

```bash
helm install workspace-mcp ./helm-chart/workspace-mcp \
  --set secrets.googleOAuth.clientId="your-client-id.apps.googleusercontent.com" \
  --set secrets.googleOAuth.clientSecret="your-client-secret"
```

The chart is contributed by the community and may lag the main codebase, so reviewers should validate the rendered manifests in `templates/deployment.yaml` against the current server expectations.

| Path | Use case | Key config surface |
|------|----------|--------------------|
| `uv run` | Local dev, quick start | CLI flags (`--tools`, tier) |
| Docker / Compose | Reproducible single-host | Image, env, volumes |
| Helm chart | Multi-replica production | `values.yaml`, OAuth secrets |

## Persistent CLI

`core/cli.py` introduces a **persistent CLI wrapper** named `workspace-cli`. It addresses a recurring pain point: the default `fastmcp list/call` flow re-triggers the full browser-based OAuth handshake on every invocation, which is impractical for scripting.

The wrapper reuses the project's existing `FileTreeStore` and `FernetEncryptionWrapper` to cache OAuth tokens on disk under `~/.workspace-mcp/cli-tokens/`, encrypted with a randomly generated Fernet key stored at `~/.workspace-mcp/.cli-encryption-key` with `0o600` permissions [Source: [core/cli.py:1-60](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/cli.py)]. Typical usage:

```bash
uv run workspace-cli list
uv run workspace-cli call search_gmail_messages query="is:unread" max_results=5
```

The default endpoint is `http://localhost:8000/mcp` and is overridable for remote servers. The `make_sanitized_file_store` helper from `core/storage.py` is imported to ensure the on-disk tree is namespaced and safe to share between CLI invocations.

## Storage Backends and Server Configuration

`core/server.py` documents the server's storage-backend selection logic for the OAuth proxy. The choice is driven by environment variables:

- `WORKSPACE_MCP_OAUTH_PROXY_STORAGE_BACKEND` — selects `valkey`, `disk`, or `memory` (default).
- `WORKSPACE_MCP_OAUTH_PROXY_VALKEY_HOST` / `_PORT` / `_DB` / `_USE_TLS` — connection parameters when Valkey is chosen.
- `FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY` — overrides the JWT signing key for the OAuth provider.

The server imports `ValkeyStore` from `key_value.aio.stores.valkey` when Valkey is selected, falling back to an encrypted disk or in-memory store otherwise [Source: [core/server.py:1-80](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/server.py)]. A Fernet key is derived from the FastMCP JWT issuer, and the resulting `FernetEncryptionWrapper` is reused for both server and CLI token storage, ensuring a single key material strategy.

## Operations: Tool Tiers, Logging, and Resilience

**Tool tiers.** `core/tool_tier_loader.py` and `core/tool_tiers.yaml` implement a three-level tier system — `core`, `extended`, and `complete` — that filters which tools and services are loaded. `ToolTierLoader.get_tools_up_to_tier()` returns the union of tools up to and including a given tier, optionally filtered by service name [Source: [core/tool_tier_loader.py:1-100](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_tier_loader.py)]. For example, the `appscript` service in `tool_tiers.yaml` exposes `list_script_projects`, `get_script_project`, and `run_script_function` at the `core` level, while `manage_deployment` and `list_script_processes` are reserved for the `extended` tier.

**Conditional registration.** `core/tool_registry.py` wires tiers into FastMCP via the `conditional_tool(server, tool_name)` decorator. If the tool name is not in the enabled set, the decorator is a no-op; otherwise it calls `server.tool()`. This allows a single binary to ship the full tool surface and load only the configured subset at runtime [Source: [core/tool_registry.py:1-50](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/core/tool_registry.py)].

**Logging.** `core/log_formatter.py` provides `setup_enhanced_logging` and rewrites common messages — such as "Tier 'core' resolved to N tools across M services" — into a more readable form, which is invaluable for tier-filtered production logs.

**Error handling and retries.** `core/utils.py` defines `TransientNetworkError` and `UserInputError`, defines a constant `GOOGLE_API_WRITE_RETRIES = 3`, and centralizes HTTP error wrapping through `handle_http_errors`. `core/api_enablement.py` parses `HttpError` payloads to extract the unfriendly API service name and project ID, then returns a direct enablement link from the `API_ENABLEMENT_LINKS` table — turning opaque 403s into actionable guidance.

```mermaid
flowchart LR
  A[Operator] -->|uv / docker / helm| B[Workspace MCP Server]
  B -->|conditional_tool| C{Tier filter}
  C -->|core| D[Core tools]
  C -->|extended| E[Extended tools]
  B -->|FernetEncrypted| F[Storage backend]
  F --> G[(Valkey)]
  F --> H[(Disk)]
  F --> I[(Memory)]
  A -->|workspace-cli| J[CLI client]
  J -->|cached token| B
```

## Common Failure Modes

1. **OAuth consent screen not configured** — the first `workspace-cli` or server start will fail unless the Google Cloud project has a configured consent screen and the user is added as a test user [Source: [gappsscript/README.md:1-150](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)].
2. **Valkey host unreachable** — selecting `valkey` without a reachable host crashes startup; fall back to `disk` or `memory` for local development.
3. **Tier mismatch** — calling a tool that is not in the active tier produces no registration; verify with `workspace-cli list` and adjust the `--tools` flag or `tool_tiers.yaml`.
4. **Stale Helm chart** — the chart is community-maintained and may be out of date; always cross-check `values.yaml` against current server env vars.
5. **Trigger code generation only** — Apps Script has no API for direct trigger management; operators must use `generate_trigger_code` and apply the snippet manually [Source: [gappsscript/README.md:1-200](https://github.com/taylorwilsdon/google_workspace_mcp/blob/main/gappsscript/README.md)].

## See Also

- Authentication & OAuth Scopes
- Tool Tiers & Conditional Registration
- Google Apps Script MCP Tools
- Helm Chart Values Reference

---

<!-- evidence_pipeline_checked: true -->

---

## Pitfall Log

Project: taylorwilsdon/google_workspace_mcp

Summary: Found 14 structured pitfall item(s), including 2 high/blocking item(s). Top priority: Security or permission risk - Security or permission risk requires verification.

## 1. Security or permission risk - Security or permission risk requires verification

- Severity: high
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_c7cc59a60e134e2d8daa4b1fbb038c4e | https://github.com/taylorwilsdon/google_workspace_mcp/issues/604

## 2. Security or permission risk - Security or permission risk requires verification

- Severity: high
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_bb95e291c12f441191119371ecf3fdc9 | https://github.com/taylorwilsdon/google_workspace_mcp/issues/816

## 3. Identity risk - Identity risk requires verification

- Severity: medium
- Evidence strength: runtime_trace
- Finding: Project evidence flags a identity risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Repro command: `uvx workspace-mcp`
- Evidence: identity.distribution | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 4. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_f3686b24c6314e76aee6eb72664eb2e7 | https://github.com/taylorwilsdon/google_workspace_mcp/issues/712

## 5. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_eb0e4e44f51548aeb444b28a6b6cf5f0 | https://github.com/taylorwilsdon/google_workspace_mcp/issues/820

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 8. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 9. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 10. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_1b6109e8bc6f4b698e60b4cf90393c37 | https://github.com/taylorwilsdon/google_workspace_mcp/issues/827

## 11. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_f4a076284fec42488a643bcc04b7352b | https://github.com/taylorwilsdon/google_workspace_mcp/issues/810

## 12. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_c86f99cee72440648873011ec5661efe | https://github.com/taylorwilsdon/google_workspace_mcp/issues/809

## 13. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

## 14. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:973788136 | https://github.com/taylorwilsdon/google_workspace_mcp

<!-- canonical_name: taylorwilsdon/google_workspace_mcp; human_manual_source: deepwiki_human_wiki -->
