gmail-multi
by DavidOloyede
README.md
# gmail-multi
Give Claude more than one Gmail account: a small server that runs on your own computer and lets Claude Code and Claude Desktop search and read several named Gmail inboxes.

[▶ Open the interactive walkthrough](https://davidoloyede.github.io/gmail-multi-mcp/)
**Status:** v0.1 · read-only · 4 tools · tested on macOS with Claude Code and Claude Desktop.
---
## Why this exists
Claude's built-in Gmail connector holds one Google account at a time. If you have a personal inbox and a work inbox, you can only connect one of them.
gmail-multi runs locally and holds several accounts, each with a short name such as `personal` or `work`. Every tool requires the account name, so Claude always says which inbox it's reading and results from different accounts never get mixed up.
## How it works
```mermaid
flowchart LR
CC["Claude Code"] -- "stdio" --> S
CD["Claude Desktop"] -- "stdio" --> S
S["gmail-multi<br/>(node src/index.js)"] --> TP["~/.gmail-mcp/token-personal.json"]
S --> TW["~/.gmail-mcp/token-work.json"]
S -- "HTTPS" --> G["Gmail API"]
```
gmail-multi is an [MCP](https://modelcontextprotocol.io) server, which is a program Claude starts on your computer and talks to through stdin/stdout ("stdio"). When Claude calls a tool such as `gmail_search` with `account: "work"`, the server loads that account's token file from `~/.gmail-mcp` and makes the request straight to Google's Gmail API. You create your own Google Cloud app, so the login keys belong to you and not to the author of this project. **Your tokens never leave your computer, and nothing is sent to the author.** The only network traffic goes to Google. The email content Claude reads becomes part of your Claude conversation, the same as with any other connector.
## Requirements
- **macOS or Linux.** These instructions use macOS menu names. Linux works the same way.
- **Node.js 18 or newer.** Run `node --version` to check. If it isn't installed, get it from [nodejs.org](https://nodejs.org).
- **Claude Code and/or Claude Desktop.**
- **One Google account per inbox** you want to connect.
- **About 45 minutes** the first time. Most of that is the Google Cloud setup, which you only do once.
---
## Setup
### Step 1: Clone and install
Open **Terminal** and run:
```bash
git clone https://github.com/DavidOloyede/gmail-multi-mcp.git ~/gmail-mcp-server
cd ~/gmail-mcp-server
npm install
```
`npm install` downloads the dependencies into a `node_modules` folder. If it finishes without errors, you're ready.
You can put the folder anywhere you like. Just run the later commands from inside it.
### Step 2: Create your own Google Cloud app
This gives you a private "app" that is allowed to ask Google for read access to your Gmail. You only do it once, and the same app works for all of your accounts.
1. **Create a project.** Go to [console.cloud.google.com](https://console.cloud.google.com) and sign in with any Google account. In the top bar, click the **project picker** (next to the Google Cloud logo), then **New Project**. Name it something like `gmail-multi` and click **Create**. When it's ready, make sure the project picker shows your new project.
2. **Enable the Gmail API.** Open the ☰ menu → **APIs & Services** → **Library**. Search for **Gmail API**, click it, then click **Enable**.
3. **Branding.** Open the ☰ menu → **Google Auth Platform** → **Branding**. (If you see a **Get started** button instead, click it. The wizard asks the same questions.) Enter an **App name** such as `gmail-multi` and choose your email as the **User support email**. Fill in the **Developer contact information** email and click **Save** (or **Create** in the wizard).
4. **Audience.** Click **Audience** in the left sidebar. The user type should be **External**. Under **Publishing status**, click **Publish app**, then **Confirm**.
*Why publish?* While an app is in **Testing** mode, Google expires its logins every 7 days, so you'd have to sign in again every week. A published app keeps working. Publishing does **not** make your app public or listed anywhere. It just means anyone with the link *could* sign in, and you're the only one with the link.
5. **Data Access.** Click **Data Access** → **Add or remove scopes**. In the **Manually add scopes** box at the bottom, paste
`https://www.googleapis.com/auth/gmail.readonly`
and click **Add to table**. Make sure it's checked, click **Update**, then **Save**. Add **only** this scope.
6. **Clients.** Click **Clients** → **Create client**. For **Application type** choose **Desktop app**, give it any name, and click **Create**. In the dialog that appears, click **Download JSON**. The file lands in your Downloads folder with a name like `client_secret_1234…apps.googleusercontent.com.json`.
Download it now, because Google may not show the secret again later. If you lose it, create a new client.
### Step 3: Store the key file privately
The JSON file you just downloaded is your app's key. Keep it in a private folder outside the project so it can never be committed to git:
```bash
mkdir -p ~/.gmail-mcp && chmod 700 ~/.gmail-mcp
mv ~/Downloads/client_secret_*.json ~/.gmail-mcp/credentials.json
chmod 600 ~/.gmail-mcp/credentials.json
ls -la ~/.gmail-mcp
```
(If `mv` complains that the target is not a directory, you have more than one `client_secret_*.json` in Downloads. Delete the old ones and try again.)
`ls -la ~/.gmail-mcp` should show something like this. `drwx------` on the folder and `-rw-------` on the file mean only you can read them:
```
drwx------ 3 you staff 96 Oct 6 12:00 .
drwxr-x---+ 40 you staff 1280 Oct 6 12:00 ..
-rw------- 1 you staff 403 Oct 6 12:00 credentials.json
```
### Step 4: Connect each inbox
From inside the project folder, run the login script once per account:
```bash
node src/auth.js personal
```
Here's what happens:
1. The terminal prints a long link that starts with `https://accounts.google.com/o/oauth2/v2/auth?...`. Open it: hold **⌘** and click it, or copy and paste it into your browser. The script waits while you finish in the browser.
2. Choose the Google account you want to call `personal`.
3. You'll see **"Google hasn't verified this app."** This is expected. The app is the one *you* created in Step 2, and Google only verifies apps that go through its public review. Click **Advanced**, then **Go to gmail-multi (unsafe)** (it shows whatever app name you chose).
4. On the next screen, if there's a checkbox next to **View your email messages and settings**, tick it. Then click **Continue**.
5. The browser shows **Done**, and the terminal prints `Saved token to /Users/you/.gmail-mcp/token-personal.json (chmod 600).`
Now do the second account. **Use a private/incognito window** (⌘⇧N in Chrome or Safari) so Google doesn't quietly reuse the account you're already signed into:
```bash
node src/auth.js work
```
Copy the printed link, paste it into the incognito window, sign in with your *work* Google account, and repeat steps 3–5.
### Step 5: Register with Claude
Claude Code and Claude Desktop keep **separate** lists of servers. Set up either one, or both.
**Claude Code.** From inside the project folder, run:
```bash
claude mcp add --scope user gmail-multi -- node "$(pwd)/src/index.js"
```
`$(pwd)` fills in the full path to the folder you're in. `--scope user` makes the server available in every project, not just this folder.
**Claude Desktop:**
1. Open Claude Desktop → **Settings** → **Extensions**.
2. Click **Advanced settings**.
3. Under **Extension Developer**, click **Install Unpacked Extension**.
4. Choose this project folder (`gmail-mcp-server`) and click **Open**. Claude Desktop reads `manifest.json` from it.
5. **gmail-multi** now appears in your extensions list. Make sure it's enabled.
### Step 6: Check it works
In Claude Code, start a session and type:
```
/mcp
```
You should see **gmail-multi** marked **connected** with **4 tools**: `gmail_search`, `gmail_get_message`, `gmail_list_labels`, `gmail_create_draft`.
Then ask something like:
> What's unread in both my personal and work inboxes from the last 7 days?
Claude should call `gmail_search` twice, once with `account: "personal"` and once with `account: "work"`, and summarize each inbox separately.
---
## Already using Claude's built-in Gmail connector?
If Claude's built-in Gmail connector is also turned on, Claude may use it instead of gmail-multi, and then it only sees one inbox. To fix this, stop the built-in connector from handling the overlapping tools:
1. In Claude, go to **Settings** → **Connectors** → **Gmail**.
2. Under tool permissions, set these four to **Block** (⊘):
- **Search email threads**
- **Get email message**
- **List labels**
- **Create draft email**
Now requests like "search both inboxes" go to gmail-multi.
## Tools
Every tool requires `account`, which must be one of the names defined in `ACCOUNTS` in [`src/config.js`](src/config.js) (`"personal"` or `"work"` by default).
| Tool | Parameters | What it does |
|---|---|---|
| `gmail_search` | `account` (string, required)<br>`query` (string, required): Gmail search syntax, e.g. `is:unread newer_than:7d`<br>`maxResults` (integer 1–50, optional, default `10`) | Searches the account and returns each match's id, threadId, subject, from, date and snippet. It does not return full bodies. |
| `gmail_get_message` | `account` (string, required)<br>`messageId` (string, required): an `id` from `gmail_search` | Returns one message's subject, from, to, date and plain-text body. HTML-only emails come back with an empty body. |
| `gmail_list_labels` | `account` (string, required) | Lists the account's labels (INBOX, SENT, your custom labels, and so on). |
| `gmail_create_draft` | `account` (string, required)<br>`to` (string, required)<br>`subject` (string, required)<br>`body` (string, required, plain text) | Creates a draft. It **does not send**. |
**`gmail_create_draft` needs the `gmail.compose` scope**, which the default read-only setup doesn't grant. Until you add it, the tool returns a message explaining how. To enable drafting:
1. Google Cloud Console → **Google Auth Platform** → **Data Access** → **Add or remove scopes**, add `https://www.googleapis.com/auth/gmail.compose`, then **Update** → **Save**.
2. In `src/config.js`, add `"https://www.googleapis.com/auth/gmail.compose",` to the `SCOPES` list.
3. Re-run `node src/auth.js personal` and `node src/auth.js work` (incognito for the second). Old logins only ever granted read access, so each account has to approve the new permission.
4. Restart Claude (see [Adding more accounts](#adding-more-accounts) for how).
## Adding more accounts
1. Open `src/config.js` and add an entry to `ACCOUNTS`. The comment above it shows the format:
```js
side: {
label: "Side project account",
tokenPath: path.join(CONFIG_DIR, "token-side.json"),
},
```
The key (`side`) is the name you and Claude will use. Keep it short and lowercase.
2. Connect it in an incognito window:
```bash
node src/auth.js side
```
3. Restart the server so Claude sees the new name. In Claude Code, start a new session or type `/mcp` and reconnect gmail-multi. In Claude Desktop, turn the extension off and on in **Settings → Extensions**, or quit and reopen the app.
## Security and privacy
**What's stored, and where.** Everything lives in `~/.gmail-mcp/` on your computer, outside the project folder:
| File | Contents | Permissions |
|---|---|---|
| `~/.gmail-mcp/` | the folder | `700` (only you can open it) |
| `credentials.json` | your Google Cloud app's client ID and client secret (Step 3) | `600` (only you can read it) |
| `token-<account>.json` | one per account: a refresh token and a short-lived access token | `600`, set automatically by `auth.js` |
**No secrets in this repo.** Every user creates their own Google Cloud app and their own logins, so there's nothing secret to ship. `.gitignore` also blocks `credentials.json`, `client_secret*.json`, `token*.json` and `.env` files, in case one ever ends up in the folder by mistake.
**Where data goes.** The server talks only to Google (OAuth and the Gmail API). It has no analytics or telemetry and nothing is sent to the author. The login script (`auth.js`) briefly listens on `127.0.0.1:53682`, which only your own computer can reach, to receive Google's sign-in redirect, and stops as soon as you've signed in. Messages Claude reads with these tools are sent to Claude as part of your conversation.
**Scope.** By default it asks for `https://www.googleapis.com/auth/gmail.readonly` only. That lets it read messages and labels. It cannot send, delete, archive or change settings. It's read-only on purpose: an assistant that can only read can't do anything you didn't expect. Drafting is opt-in (see [Tools](#tools)).
**Revoke access.** For each Google account you connected, go to [myaccount.google.com/permissions](https://myaccount.google.com/permissions), find your app's name, and click **Delete all connections** (or **Remove access**).
**Delete local data:**
```bash
rm -rf ~/.gmail-mcp
claude mcp remove gmail-multi --scope user # if you registered with Claude Code
```
For Claude Desktop, remove the extension in **Settings → Extensions**. You can also delete the Google Cloud project at [console.cloud.google.com](https://console.cloud.google.com) → **IAM & Admin** → **Settings** → **Shut down**.
## Troubleshooting
**`command not found: claude`**
Claude Code isn't installed, or your terminal can't find it. Install Claude Code by following Anthropic's Claude Code setup instructions, then open a **new** terminal window and try again. If you only use Claude Desktop, skip the `claude mcp add` step entirely.
**The server connects but shows no tools, or fails to connect**
Run the server by hand from the project folder to see the real error:
```bash
node src/index.js
```
If it's healthy it prints `gmail-multi-mcp ready (accounts: personal, work)` and then waits. Press **Ctrl+C** to stop it. If it prints an error instead, the usual causes are a skipped `npm install` (`Cannot find package ...`), Node older than 18 (`node --version`), or a typo in `src/config.js`. Fix that, then reconnect: `/mcp` in Claude Code, or turn the extension off and on in Claude Desktop.
**`No token for "work" yet. Run: node src/auth.js work`**
That account hasn't been connected yet, or its token file was deleted. Run the command it suggests (Step 4).
**`invalid_grant`**
Google has stopped accepting that account's saved login. Common reasons:
- You changed that Google account's password.
- Your Google Cloud app is still in **Testing** mode, where logins expire after 7 days. Publish it (Step 2, Audience).
- The token wasn't used for about 6 months.
- You removed the app's access at myaccount.google.com/permissions.
Fix: re-run `node src/auth.js <account>` for that account, then restart the server.
**`Error: listen EADDRINUSE ... 127.0.0.1:53682` (port already in use)**
Another copy of `auth.js` is probably still waiting in a different terminal tab. Press **Ctrl+C** there. To find whatever is holding the port:
```bash
lsof -i :53682
kill <PID> # the number in the PID column
```
**The wrong Gmail account got connected**
Your browser reused an account you were already signed into. Delete that account's token file and connect again in an incognito window:
```bash
rm ~/.gmail-mcp/token-work.json
node src/auth.js work
```
**`Can't find /Users/you/.gmail-mcp/credentials.json`**
The key file from Step 2 isn't in place. Redo Step 3.
## Roadmap
The [interactive walkthrough](https://davidoloyede.github.io/gmail-multi-mcp/) shows today's from-source install and the planned one-click install paths.
- **v0.1 (now):** search, read and list labels across named accounts. Drafting with an extra scope.
- **v0.2:** send mail from a chosen account. The account list moves out of code into a config file.
- **v0.3:** reply, forward, labels, trash.
- **v1.0:** sign in to Google from inside a Claude chat instead of the terminal, and a one-click `.mcpb` install for Claude Desktop.
## License
[MIT](LICENSE) © 2026 David Oloyede
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues