Google Workspace MCP
by yaniv-tg
README.md
# google-workspace-mcp
MCP server for Google Workspace with persistent multi-account OAuth, OS keychain storage, and health monitoring.
## Why
AI assistants lose Google Workspace authentication between sessions. Users with multiple Google accounts must re-authenticate manually every time. This MCP server solves both problems:
- **Persistent auth** — OAuth tokens stored in OS keychain, survive restarts
- **Multi-account** — Unlimited Google accounts with human-readable profile labels
- **Health monitoring** — Three-layer defense: startup check, background heartbeat, graceful tool failure
- **Setup in 5 minutes** — Interactive wizard handles everything
- **Zero secrets in code** — All credentials live in OS keychain or env vars, never on filesystem
## Prerequisites
- **Node.js 18+**
- **GCP project** with OAuth 2.0 credentials (Desktop application type)
- **Enabled APIs**: Gmail, Calendar, Drive, Sheets, People
- **OS keychain** (macOS Keychain, Windows Credential Vault, or Linux libsecret) — falls back to encrypted file store
## Quick Start
```bash
# Install globally
npm install -g google-workspace-mcp
# Run the setup wizard (5 minutes)
gws-mcp setup
# Or manually:
gws-mcp auth add work --scopes gmail,calendar,drive --email you@company.com
gws-mcp auth add personal --scopes gmail,drive --email you@gmail.com
gws-mcp auth status
```
Add to your Claude Code `settings.json`:
```json
{
"mcpServers": {
"google-workspace": {
"command": "npx",
"args": ["-y", "google-workspace-mcp"]
}
}
}
```
## Available Tools
### Admin Tools
| Tool | Description |
|------|-------------|
| `list_profiles` | Show all profiles with health status |
| `manage_profiles` | Add/edit/remove profile, change scopes, set business rules |
| `auth_status` | Detailed auth health for one or all profiles |
| `configure_notifications` | Set notification channels, heartbeat interval |
| `configure_permissions` | Set business rules per profile per service |
### Gmail
| Tool | Description |
|------|-------------|
| `gmail_search` | Search messages with Gmail query syntax |
| `gmail_read` | Read full message with HTML link extraction |
| `gmail_read_thread` | Read entire thread — deduplicated, attributed |
| `gmail_send` | Send new email |
| `gmail_reply` | Reply to a message (handles threading) |
| `gmail_forward` | Forward a message |
| `gmail_list_labels` | List all labels |
| `gmail_modify_labels` | Add/remove labels |
### Calendar
| Tool | Description |
|------|-------------|
| `calendar_list_events` | List events in date range |
| `calendar_get_event` | Get event details |
| `calendar_create_event` | Create event with attendees |
| `calendar_update_event` | Modify existing event |
| `calendar_delete_event` | Delete/cancel event |
| `calendar_free_busy` | Check availability across profiles |
### Drive
| Tool | Description |
|------|-------------|
| `drive_list_files` | List/search files (supports shared drives) |
| `drive_get_file` | Get file metadata |
| `drive_read_file` | Read content — text, Docs export, PDF extraction |
| `drive_upload_file` | Upload a file |
| `drive_create_folder` | Create folder |
| `drive_share` | Share file/folder |
### Sheets
| Tool | Description |
|------|-------------|
| `sheets_read_range` | Read cell range |
| `sheets_append_row` | Append row |
| `sheets_update_range` | Update cell range |
| `sheets_batch_update` | Full batchUpdate API |
| `sheets_create` | Create new spreadsheet |
### Contacts
| Tool | Description |
|------|-------------|
| `contacts_search` | Search contacts |
| `contacts_list` | List contacts |
## Configuration
### Profiles
Profiles are stored in `~/.gws-mcp/profiles.json` (metadata only — no tokens):
```json
{
"profiles": [
{
"label": "work",
"email": "you@company.com",
"scopes": ["gmail", "calendar", "drive"],
"rules": {
"gmail": { "read": true, "send": true, "delete": false },
"calendar": { "read": true, "create": true, "delete": false },
"drive": { "read": true, "upload": true, "delete": false }
}
}
]
}
```
### Two-Layer Permission Model
1. **OAuth scopes** — What Google allows (set during `auth add`)
2. **Business rules** — What you allow Claude to do (set in profiles.json or via `manage_profiles` tool)
Business rules are enforced even if the OAuth token technically allows more.
### Notifications
Config in `~/.gws-mcp/config.json`:
```json
{
"notifications": {
"channels": ["desktop", "log"],
"telegram": {
"enabled": false,
"botToken": "env:GWS_MCP_TELEGRAM_BOT_TOKEN",
"chatId": "env:GWS_MCP_TELEGRAM_CHAT_ID"
},
"heartbeatIntervalMinutes": 30,
"alertOn": ["reauth_needed", "token_expiring_24h", "scope_change_detected"]
}
}
```
## CLI Commands
```bash
gws-mcp setup # Interactive wizard
gws-mcp auth add <profile> # Add account
gws-mcp auth remove <profile> # Remove account
gws-mcp auth refresh <profile> # Force token refresh
gws-mcp auth status # Health table
gws-mcp config show # Show config (redacted)
gws-mcp config set <key> <val> # Set config value
gws-mcp config reset # Reset to defaults
gws-mcp serve # Start MCP server
```
## Security
### Where Secrets Live
| Secret | Storage | In Git? |
|--------|---------|---------|
| OAuth Client ID + Secret | OS Keychain | Never |
| Access tokens | OS Keychain | Never |
| Refresh tokens | OS Keychain | Never |
| Telegram bot token | Env var | Never |
| Profile metadata | `~/.gws-mcp/profiles.json` | Never |
### Pre-Publish Audit
The `prepublishOnly` script automatically scans for leaked credentials before npm publish:
```bash
grep -rn "AIza\|ya29\.\|GOCSPX\|client_secret\|refresh_token" src/
```
## Roadmap
See [ROADMAP.md](./ROADMAP.md) for planned features.
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
## License
MIT
This server cannot be deployed