GAM MCP Server
# Google Apps Manager (GAM) TypeScript Model Context Protocol (MCP) Server
A high-performance, secure, memory-safe Model Context Protocol (MCP) server that implements Google Workspace administrative controls (Directory, Gmail, Drive, Sheets) via Domain-Wide Delegation (DWD) service account impersonation.
Designed as a modern TypeScript alternative to traditional GAM scripts, this server provides a structured, schema-validated toolset that integrates with any Model Context Protocol host (such as Antigravity or Claude Desktop).
---
## Core Architectural Features
* **Resilient Rate-Limiting**: API requests are wrapped in exponential backoff with fractional randomized jitter. The retry classifier distinguishes retryable (`429`, `5xx`, `403/quotaExceeded`, network `ECONNRESET`/`ETIMEDOUT`/etc.) from non-retryable errors (`400`, `403/forbidden`, `403/insufficientPermissions`), and honors `Retry-After` headers when the server provides one.
* **Stream-to-Disk Operations**: `StreamDiskWriter` pipes large search and audit responses line-by-line directly to local files at `0600` permissions, bypassing standard V8 heap limits to prevent Node.js Out-Of-Memory (OOM) crashes.
* **Concurrency-Limitation Gates**: A strict write-concurrency queue limited to **maximum 5 active operations** for Directory mutations, and **10 concurrent** Drive audit list pages.
* **Token-Scrubbing Filter**: Globally intercepts `stdout` and `stderr` to mask access tokens (`ya29.*`), refresh tokens (`1//0*`), ID tokens (`eyJ*.*.*`), and PEM private key blocks before any bytes are flushed. Idempotent.
* **POSIX Security Guard**: Validates service account key file permissions on startup, emitting a high-visibility security warning if the key is world- or group-accessible. Called exactly once at startup.
* **Path Allowlist**: All tool I/O paths (audit outputs, CSV imports) are resolved under `GAM_MCP_OUTPUT_DIR` (or cwd if unset). Paths that escape the root are rejected, as are any paths whose ancestry contains a symlink.
* **CSV Injection Defense**: Spreadsheet-bound output prefixes leading `=`, `+`, `-`, `@`, `\t`, `\r` with a single quote per OWASP guidance, preventing formula injection when audits are opened in Excel or Sheets.
* **JWT Client Cache**: DWD JWT instances are cached per `(subject, scopes)` so the underlying `google-auth-library` access-token cache is reused across many calls within a single audit.
* **Multi-line CSV Reader**: The Sheets exporter correctly joins records that span multiple physical lines (RFC 4180 §2.6).
* **Structured Logging**: A stderr-only logger emits human-readable text in `test` mode and single-line JSON in `prod` mode (set via `NODE_ENV` or `GAM_MCP_ENV`). Log level is gated via `--log-level` / `GAM_MCP_LOG_LEVEL`.
---
## Tool Catalog (13 Administrative Tools)
### Directory & Group Management
* **`gam_admin_create_user`**: Creates user accounts. `password` is optional — if omitted, a cryptographically secure 32-character base64url password (~192 bits of entropy) is generated and returned ONCE in the response.
* **`gam_admin_update_ou`**: Moves a user or re-parents an OU. Requires explicit `targetType: 'user' | 'ou'` (no auto-detection from `@`).
* **`gam_admin_sync_group_members`**: Computes membership diffs and syncs concurrently up to the 5-concurrency write limit. If a group's membership exceeds the `MAX_PAGES_LIMIT` read cap, the diff would be computed against partial membership: a dry-run returns `truncated: true` with a warning, and a real sync is **refused** to avoid a destructive partial sync.
* **`gam_admin_print_users`**: Paginated user listing (up to `MAX_PAGES_LIMIT` pages) in CSV or JSON.
* **`gam_admin_print_groups`**: Paginated group listing in CSV or JSON.
* **`gam_admin_print_group_members`**: Paginated active-member listing in CSV or JSON.
### Gmail Compliance & Mail Auditing
* **`gam_gmail_search_messages`**: Searches a mailbox and returns metadata + snippets of the first N results in CSV or JSON.
* **`gam_gmail_get_message`**: Fetches details for a single email, decoding base64url MIME parts recursively (depth-capped at 20).
* **`gam_gmail_bulk_delete`**: Batch deletes emails matching a query in chunks of 1000 IDs (Gmail's API limit). Default dry-run shows up to 15 sample previews. When more messages match than can be enumerated within the `MAX_PAGES_LIMIT` page cap, the response sets `truncated: true` and the message instructs you to re-run (or narrow the query) to delete the remainder.
### Drive Security Auditing
* **`gam_drive_list_files`**: Lists file metadata. Accepts `corpora: 'user' | 'domain' | 'drive' | 'allDrives'` to widen the search scope (use `allDrives` for Shared Drives).
* **`gam_drive_audit_permissions`**: Memory-safe permission audit. Streams flattened rows to a file under `GAM_MCP_OUTPUT_DIR` with the inherited-ancestry cache active across the run. Also accepts `corpora`.
### Sheets & Reports
* **`gam_export_audit_to_sheets`**: Streams a local CSV (which MUST live under `GAM_MCP_OUTPUT_DIR`) to a Sheet tab in safe 2000-row chunks. Auto-creates missing tabs.
* **`gam_read_admin_sheet`**: Reads a worksheet range to feed targeting data back into administrative automation runs.
**Note:** Gmail, Drive, and Sheets tools no longer accept `adminUserEmail` — the DWD impersonation subject is always the named mailbox/Drive/Sheet owner (`userEmail`).
---
## Google Workspace Setup (Domain-Wide Delegation)
To authorize this service account, a Google Workspace Super-Admin must configure Domain-Wide Delegation (DWD) inside the Google Workspace Admin Console.
### 1. Create a Service Account in GCP
1. Go to the [Google Cloud Console](https://console.cloud.google.com/).
2. Create or select a project (e.g., `gam-mcp`).
3. Enable the following APIs:
* **Admin SDK API** (`admin.googleapis.com`)
* **Gmail API** (`gmail.googleapis.com`)
* **Google Drive API** (`drive.googleapis.com`)
* **Google Sheets API** (`sheets.googleapis.com`)
4. Navigate to **IAM & Admin > Service Accounts** and create a Service Account (e.g., `gam-mcp-sa`).
5. Generate and download a **JSON credentials key**. Save it securely.
6. Set secure POSIX file permissions:
```bash
chmod 0600 ~/secrets/oauth2service.json
```
7. Note the **Client ID** (Unique ID) of the service account.
### 2. Configure Domain-Wide Delegation (DWD)
1. Log into the [Google Workspace Admin Console](https://admin.google.com/) as a Super Admin.
2. Go to **Security > Access and data control > API controls**.
3. Under **Domain-wide delegation**, click **Manage Domain Wide Delegation**.
4. Click **Add new**, enter the **Client ID**, and paste these OAuth scopes:
```text
https://www.googleapis.com/auth/admin.directory.user,
https://www.googleapis.com/auth/admin.directory.group,
https://www.googleapis.com/auth/admin.directory.group.member,
https://www.googleapis.com/auth/admin.directory.orgunit,
https://www.googleapis.com/auth/drive.readonly,
https://www.googleapis.com/auth/gmail.readonly,
https://mail.google.com/,
https://www.googleapis.com/auth/spreadsheets,
https://www.googleapis.com/auth/spreadsheets.readonly
```
*(`https://mail.google.com/` is only required for `gam_gmail_bulk_delete`.)*
5. Save the delegation.
---
## Installation & Local Execution
Requires **Node.js 20+ LTS** (enforced via `package.json` `engines`).
```bash
cd gam-mcp
npm install
npm run build
npm run test # unit + integration
```
---
## Configuration
The server resolves settings in this precedence order (highest wins):
1. **CLI flags** (see below)
2. **Environment variables**
3. **Config file** (`--config <path>`)
4. **Built-in defaults**
### CLI flags
```
gam-mcp-server [options] [credentials.json]
OPTIONS:
-c, --credentials <path> Service-account JSON key file.
--config <path> Path to a key=value (or key: value) config file.
--log-level <level> error | warn | info | debug
--read-only Block all mutating tool invocations.
--dry-run Treat mutating tools as dry-runs by default.
-h, --help Show help and exit.
-v, --version Show version and exit.
```
### Environment variables
| Variable | Purpose |
|---|---|
| `GAM_MCP_CREDENTIALS` | Path to the service-account JSON key. |
| `GOOGLE_APPLICATION_CREDENTIALS` | Same, but standard GCP env var. |
| `GAM_MCP_CONFIG` | Path to a config file (same format as `--config`). |
| `GAM_MCP_LOG_LEVEL` | `error` \| `warn` \| `info` \| `debug` |
| `GAM_MCP_READ_ONLY` | `1`/`true`/`yes` to enable read-only mode. |
| `GAM_MCP_OUTPUT_DIR` | Allowlist root for tool I/O. Defaults to cwd. |
| `GAM_MCP_ENV` / `NODE_ENV` | `test` (default, text logs) or `prod` (JSON logs). |
A template is provided in `.env.example`.
### Config file format
Lines are `key = value` or `key: value`. `#` and `;` introduce comments.
```ini
credentials = /Users/me/secrets/oauth2service.json
log_level = info
read_only = false
output_dir = /Users/me/gam-mcp-audits
```
---
## Connecting to an MCP Host
### Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
```json
{
"mcpServers": {
"gam-mcp": {
"command": "node",
"args": [
"/Users/yourname/src/gam-mcp/build/index.js",
"--log-level", "info"
],
"env": {
"GAM_MCP_CREDENTIALS": "/Users/yourname/secrets/oauth2service.json",
"GAM_MCP_OUTPUT_DIR": "/Users/yourname/gam-mcp-audits"
}
}
}
}
```
### Antigravity
Register the server inside your Antigravity MCP registry, ensuring the absolute path to `build/index.js` is correct.
---
## Security & Data Safety Standards
* **Read-Only Command Gate**: When enabled (via `--read-only` or `GAM_MCP_READ_ONLY`), all mutating operations are blocked at the executor level. Dry-runs still proceed.
* **Fail-Safe Dry-Runs**: All mutating tools default to `dryRun: true`. Bulk delete additionally surfaces 15 sample previews on dry-run.
* **Stderr-Only Logging**: The MCP stdio transport requires a pristine stdout. The logger writes ONLY to stderr; stdout is reserved for JSON-RPC.
* **Token Scrubbing**: Every byte written to stdout/stderr is scanned for known token patterns and masked.
* **Output Path Allowlist**: Audit writes and CSV imports cannot escape `GAM_MCP_OUTPUT_DIR`. Symlink-bearing paths are rejected. Files are created with mode `0600`.
* **Closed-By-Default Error Policy**: Errors are returned to MCP callers as text content with `isError: true`; full stack traces (including `cause` chains) go to stderr at `debug`/`warn` levels.
---
## Project files
| File | Purpose |
|---|---|
| `AGENT.md` | Original developer specification (historical roadmap). |
| `README.md` | This file (operational reference). |
| `task.md` | Live status tracker. |
| `implementation_plan.md` | Architectural design notes. |
| `walkthrough.md` | Verification log per release. |
| `.env.example` | Environment template. |
---
## License
MIT.
TDQS
Scored across 13 tools
Each tool targets a distinct Google service and operation (Admin, Drive, Gmail, Sheets), with no overlapping functionality. Tools like `gam_admin_print_groups` and `gam_admin_print_group_members` are clearly differentiated by object type.
All tools follow a consistent `gam_<service>_<action>[_<object>]` pattern in snake_case, using descriptive verbs like create, print, sync, update, audit, list, export, and read.
With 13 tools covering Admin, Drive, Gmail, and Sheets operations, the tool count is well-scoped for a Google Workspace administration server—neither too sparse nor overly heavy.
The tool set covers common admin tasks like user creation, group management, drive auditing, and Gmail operations. Minor gaps exist, such as missing user deletion or group creation, but core workflows are well-supported.