Skip to main content
Glama
Vinksj

gmail-multi-mcp

by Vinksj
README.md
# gmail-multi-mcp

Connect **multiple Gmail accounts** to Claude (or any [MCP](https://modelcontextprotocol.io)
client) from one local server. The official Gmail connector only supports a single Google
account — this lets you search, read, draft, send, label, and organize mail across as many
accounts as you like, each addressed by a friendly alias.

Your OAuth tokens are stored **locally on your machine only** — never uploaded anywhere.

## Features

- šŸ”¢ **Unlimited accounts** — every tool takes an `account` parameter (`"personal"`, `"work"`, …)
- šŸ”Ž **Search & read** — full Gmail search syntax, thread/message reading, attachment download
- āœļø **Compose** — create/list/delete drafts, send mail, replies with correct threading headers
- šŸ·ļø **Organize** — full label management, archive, trash
- šŸ” **Local-first** — standard Google OAuth; tokens live in `~/.gmail-mcp/`, chmod 600
- 🧩 **22 tools**, works with Claude Code, Claude Desktop, Cursor, and any MCP client

## Prerequisites

- **Node.js ≄ 20**
- A Google account (and a free Google Cloud project — setup below)

## 1. Install

```bash
git clone https://github.com/Vinksj/claude-gmail-multi.git
cd claude-gmail-multi
npm install
npm run build
```

## 2. Create your Google OAuth app (one-time, ~10 min)

You register one OAuth "app" with Google; it then works for all the accounts you connect.

1. Go to [console.cloud.google.com](https://console.cloud.google.com) → create a project (e.g. `gmail-mcp`).
2. **APIs & Services → Library** → search **Gmail API** → **Enable**.
3. **APIs & Services → OAuth consent screen**:
   - User type **External** → Create.
   - App name + your support email + your contact email → Save and Continue.
   - Scopes page → Save and Continue. Test users page → Save and Continue.
4. **Publish to production:** on the OAuth consent screen, set **Publishing status → Publish app**.
   *(In "Testing" mode Google expires your refresh token every 7 days. Publishing avoids that.
   You'll click through a one-time "Google hasn't verified this app" warning per account — that's
   normal for a personal app: choose **Advanced → Continue**.)*
5. **APIs & Services → Credentials → Create Credentials → OAuth client ID**:
   - Application type **Desktop app** → Create → **Download JSON**.
6. Save that file as `~/.gmail-mcp/credentials.json`:
   ```bash
   mkdir -p ~/.gmail-mcp && chmod 700 ~/.gmail-mcp
   mv ~/Downloads/client_secret_*.json ~/.gmail-mcp/credentials.json
   chmod 600 ~/.gmail-mcp/credentials.json
   ```

> Note: newer Google Cloud UIs put these under **"Google Auth Platform"** (Branding / Audience /
> Clients) instead of "OAuth consent screen" — same steps, different labels.

## 3. Connect your accounts

```bash
npm run auth -- --alias personal --email you@gmail.com
npm run auth -- --alias work --email you@company.com
```

Each opens a browser → pick the matching Google account → approve. The optional `--email` flag
aborts if the wrong account gets authorized (an easy mistake with multi-login browsers). Connect
as many as you want; re-run any time a token is revoked.

## 4. Register with your MCP client

**Claude Code:**
```bash
claude mcp add --scope user gmail-multi -- node "$(pwd)/dist/index.js"
```

**Claude Desktop / other clients** — add to your MCP config:
```json
{
  "mcpServers": {
    "gmail-multi": {
      "command": "node",
      "args": ["/absolute/path/to/gmail-multi-mcp/dist/index.js"]
    }
  }
}
```

Tools appear as `gmail-multi`'s `search_threads`, `create_draft`, etc. Ask things like
*"search my work inbox for unread from this week"* or *"draft a reply in personal to Alice."*

## Tools

| Group | Tools |
|---|---|
| Accounts | `list_accounts`, `add_account` |
| Read | `search_threads`, `get_thread`, `get_message`, `download_attachment` |
| Compose | `create_draft`, `list_drafts`, `delete_draft`, `send_draft`, `send_message` |
| Labels | `list_labels`, `create_label`, `update_label`, `delete_label`, `label_thread`, `unlabel_thread`, `label_message`, `unlabel_message` |
| Cleanup | `archive_thread`, `trash_thread`, `trash_message` |

Every tool except `list_accounts` takes an `account` parameter (alias or email). Replies via
`replyToMessageId` get correct `In-Reply-To`/`References` headers and threading automatically.

## How it works

- One self-owned Google Cloud OAuth app (Desktop client) authorizes any number of accounts.
- Single scope: `https://www.googleapis.com/auth/gmail.modify` (read, search, drafts, send,
  labels, archive, trash — narrower than full `https://mail.google.com/`).
- Per-account refresh tokens stored in `~/.gmail-mcp/tokens/<alias>.json` (chmod 600); the
  account registry is `~/.gmail-mcp/config.json`. Nothing leaves your machine.

```
~/.gmail-mcp/
ā”œā”€ā”€ credentials.json        # your OAuth client (you add this)
ā”œā”€ā”€ config.json             # alias → email map (auto-managed)
└── tokens/<alias>.json     # per-account refresh tokens (auto-managed)
```

## Security notes

- Tokens are stored as plain files readable only by your user (chmod 600). On a single-user
  machine with full-disk encryption this is reasonable; moving token storage to the OS keychain
  is a sensible future hardening step.
- Never commit `~/.gmail-mcp/` — it lives in your home directory, outside this repo, and the
  repo's `.gitignore` excludes build artifacts and dependencies regardless.
- The `gmail.modify` scope cannot permanently delete mail — `trash_*` tools move items to Trash
  (recoverable for 30 days).

## Development

```bash
npm run build      # tsc -> dist/
npm run inspect    # MCP Inspector UI against the built server
npm run auth -- --alias <name> [--email <expected>]
```

Important: stdout is the JSON-RPC channel — never `console.log` in server code; use `console.error`.

## License

MIT Ā© Saurabh Jain

TDQS

A3.7/5.0

Scored across 22 tools

Disambiguation5/5

Every tool targets a distinct action and resource (accounts, threads, messages, drafts, labels, attachments). There is no ambiguity between similar operations like trash_thread vs trash_message or label_thread vs label_message, as the descriptions clearly differentiate the scope.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using snake_case (e.g., create_draft, list_labels, send_message). The verbs are clear and uniform, making the tool set predictable for an agent.

Tool Count4/5

With 22 tools, the server covers the core Gmail API surface comprehensively, including account management. While this is above the typical 3-15 range for a well-scoped server, each tool serves a distinct purpose and the count is justified by the multi-account complexity.

Completeness4/5

The tool set covers CRUD operations for threads, messages, drafts, and labels, plus search, attachments, and account management. Minor gaps exist (e.g., no explicit mark-as-read or spam tools), but these are handled indirectly through labeling and the core workflows are well-supported.

Maintenance

ActivityMaintained
ResponsivenessNo issues