Google Workspace MCP Server
by bread-wood
README.md
# Google Workspace MCP Server
A private, self-hosted [Model Context Protocol](https://modelcontextprotocol.io/) server that gives Claude authenticated access to Google Calendar, Gmail, Drive, Docs, Sheets, and Slides via stdio transport.
## Features
- **43 tools** across 7 Google Workspace services
- **Secure token storage**: AES-256-GCM encryption with macOS Keychain-stored keys
- **No hard deletes**: Archive/trash semantics only — Docs, Sheets, and Slides move to ARCHIVED folder, Gmail messages can be archived or trashed (30-day retention)
- **Prompt injection defense**: 5-stage sanitization pipeline for all untrusted content
- **OWASP-aligned security**: Input validation, rate limiting, structured logging, PKCE OAuth2
## Prerequisites
- Node.js >= 20
- macOS (uses Keychain for key storage)
- A Google Cloud project with OAuth credentials
## Google OAuth Setup
### 1. Create a Google Cloud Project
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Click **Select a project** → **New Project**
3. Name it (e.g., "Workspace MCP Server") and click **Create**
### 2. Enable APIs
Navigate to **APIs & Services → Library** and enable:
- Google Calendar API
- Gmail API
- Google Drive API
- Google Docs API
- Google Sheets API
- Google Slides API
### 3. Configure OAuth Consent Screen
1. Go to **APIs & Services → OAuth consent screen**
2. Click **Get started** (or **Edit App** if you already have one configured)
3. Set **User type** to **External** (or **Internal** if using Google Workspace)
4. Fill in the required fields:
- **App name**: e.g., "Workspace MCP Server"
- **User support email**: your email address
- **Developer contact email**: your email address
5. On the **Scopes** step, click **Add or remove scopes** and add:
- `https://www.googleapis.com/auth/calendar.events`
- `https://www.googleapis.com/auth/gmail.modify`
- `https://www.googleapis.com/auth/gmail.send`
- `https://www.googleapis.com/auth/gmail.labels`
- `https://www.googleapis.com/auth/gmail.settings.basic`
- `https://www.googleapis.com/auth/drive.readonly`
- `https://www.googleapis.com/auth/drive.file`
- `https://www.googleapis.com/auth/documents`
- `https://www.googleapis.com/auth/spreadsheets`
- `https://www.googleapis.com/auth/presentations`
6. Save and continue
### 4. Add Test Users (Required)
While the app is in "Testing" publishing status (before Google verification), only explicitly listed test users can authenticate. If you skip this step you will get a **403: access_denied** error saying the app "has not completed the Google verification process".
1. Go to **APIs & Services → OAuth consent screen**
2. Under the **Audience** section (or **Test users** tab), click **Add users**
3. Enter the Google account email you will authenticate with (e.g., `you@gmail.com`)
4. Click **Save**
You can add up to 100 test users. Only these accounts will be able to complete the OAuth flow while the app is in testing mode. You do **not** need to submit the app for Google verification — test users are sufficient for personal/self-hosted use.
### 5. Create OAuth Credentials
1. Go to **APIs & Services → Credentials**
2. Click **Create Credentials → OAuth client ID**
3. Choose **Desktop application**
4. Name it (e.g., "MCP Server")
5. Click **Create** and note the **Client ID** and **Client Secret**
### 6. Configure the MCP Server
Set environment variables:
```bash
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
```
Or create a config file at `~/.config/google-workspace-mcp/config.json`:
```json
{
"clientId": "your-client-id.apps.googleusercontent.com",
"clientSecret": "your-client-secret"
}
```
### 7. First Run
```bash
npm install
npm run build
npm start
```
On first run, the server will:
1. Open your browser for Google sign-in
2. Ask you to authorize the requested scopes
3. Store tokens securely in macOS Keychain + encrypted file
4. Start the MCP server on stdio
### 8. Claude Code Integration
Add to your `~/.claude/settings.json`:
```json
{
"mcpServers": {
"google-workspace": {
"command": "node",
"args": ["/path/to/google-workspace-mcp/dist/index.js"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id",
"GOOGLE_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
## Available Tools
### Gmail (13 tools)
> **Note for existing users**: The `gmail.settings.basic` scope was added to enable filter management tools. If you authenticated before this scope was introduced, you will be prompted to re-authenticate the next time your token refresh fails. Re-authentication happens automatically — simply follow the browser prompt when it appears.
- `gmail_search` — Search emails by query (up to 500 results)
- `gmail_get_message` — Get full email content by ID
- `gmail_send` — Send an email
- `gmail_create_draft` — Create a draft email
- `gmail_list_labels` — List all Gmail labels
- `gmail_archive` — Archive messages (remove from inbox)
- `gmail_modify_labels` — Add/remove labels (mark read, categorize, etc.)
- `gmail_trash` — Move messages to trash (30-day retention)
- `gmail_create_label` — Create labels and sub-labels
- `gmail_delete_label` — Delete a user-created label (messages are not deleted)
- `gmail_list_filters` — List all Gmail filters with their criteria and actions
- `gmail_delete_filter` — Delete a Gmail filter by ID (use `gmail_list_filters` to find IDs)
- `gmail_create_filter` — Create a Gmail filter with criteria and automated actions (label, archive, mark read, star, forward)
### Calendar (5 tools)
- `calendar_list_events` — List events in a time range
- `calendar_get_event` — Get full event details
- `calendar_create_event` — Create a calendar event
- `calendar_create_calendar` — Create a new calendar
- `calendar_update_event` — Update an existing event
### Drive (7 tools)
- `drive_search` — Search files in Drive
- `drive_get_file_metadata` — Get file metadata
- `drive_download` — Download/export file content
- `drive_upload` — Upload a file to Drive
- `drive_create_folder` — Create a new folder in Drive
- `drive_move` — Move a file or folder to a different parent folder
- `drive_create_pdf` — Generate a formatted PDF from text content and upload to Drive
### Docs (5 tools)
- `docs_get` — Get document content
- `docs_create` — Create a new document
- `docs_update` — Update document content
- `docs_archive` — Archive document (move to ARCHIVED folder)
- `docs_delete` — Permanently delete a document (irreversible)
### Sheets (6 tools)
- `sheets_get` — Get spreadsheet metadata
- `sheets_create` — Create a new spreadsheet
- `sheets_read_range` — Read cell values from a range
- `sheets_update_range` — Write cell values to a range
- `sheets_archive` — Archive spreadsheet (move to ARCHIVED folder)
- `sheets_delete` — Permanently delete a spreadsheet (irreversible)
### Slides (5 tools)
- `slides_get` — Get presentation content (title, slide count, extracted text)
- `slides_create` — Create a new presentation
- `slides_add_slide` — Add a slide with layout and placeholder text
- `slides_archive` — Archive presentation (move to ARCHIVED folder)
- `slides_delete` — Permanently delete a presentation (irreversible)
### Auth (1 tool)
- `auth_status` — Check authentication status and scopes
## Security
- **Controlled deletions**: Docs/Sheets/Slides support both soft archive (move to ARCHIVED folder) and permanent deletion. Gmail supports archive, trash (30-day retention), and label deletion. HTTP DELETE requests are blocked by default, with a targeted allowlist for specific safe operations (label deletion, file deletion).
- **Prompt injection defense**: All content from external sources (emails, documents, calendar events) passes through a 5-stage sanitization pipeline before being returned to the LLM.
- **Token security**: OAuth tokens are encrypted with AES-256-GCM. The encryption key is stored in macOS Keychain.
- **Rate limiting**: Per-tool rate limits prevent runaway API usage.
- **Input validation**: All tool inputs are validated with Zod schemas.
## Configuration
| Environment Variable | Default | Description |
|---|---|---|
| `GOOGLE_CLIENT_ID` | (required) | OAuth client ID |
| `GOOGLE_CLIENT_SECRET` | (required) | OAuth client secret |
| `MAX_CONTENT_LENGTH` | `50000` | Max content length before truncation |
| `AUTH_TIMEOUT_MS` | `300000` | OAuth flow timeout (ms) |
| `LOG_LEVEL` | `info` | Log level: debug, info, warn, error |
| `ARCHIVE_FOLDER_NAME` | `ARCHIVED` | Name of the archive folder in Drive |
## Troubleshooting
### "Permission denied. The requested scope may not be authorized." despite valid token
If `auth_status` shows the required scope is present but a tool still returns a 403, the Google API itself is not enabled in your Cloud project. Each Google API must be enabled separately — granting an OAuth scope is not enough.
Go to **APIs & Services → Library** in the Cloud Console and enable the API for the failing service (e.g., **Google Slides API** for `slides_*` tools). After enabling, retry immediately — no re-authentication is needed.
### Re-authenticating to pick up new scopes
If new scopes were added to the server after your initial auth, your stored token won't include them. Delete the token file to force a fresh OAuth flow:
```bash
rm ~/.config/google-workspace-mcp/tokens.enc
```
Then restart the MCP server (e.g., run `/mcp` in Claude Code). The browser will open for re-authentication — authorize all requested scopes.
## Development
```bash
npm install
npm run dev # Run with tsx (hot reload)
npm run build # Compile TypeScript
npm test # Run tests
npm run test:watch # Run tests in watch mode
```
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues