Gmail Multi-Account MCP Server
Enables Claude Desktop to interact with multiple Gmail accounts via MCP, providing tools for sending, searching, reading, labeling, filtering, thread management, drafts, and attachments. It also ensures correct thread replies and recoverable deletes.
README
Gmail Multi-Account MCP Server
A Model Context Protocol (MCP) server that enables Claude Desktop to interact with multiple Gmail accounts through secure OAuth 2.0 authentication.
Built on Konadu-Akwasi-Akuoko/gmail-multi-mcp, which is itself a fork of AlexHramovich/gmail-mcp. Full credit to both authors, and to the other projects listed under Credits whose ideas are borrowed here. MIT licensed, with the original copyright retained.
What's different in this version
Most Gmail MCP servers are single-account, and several share a family of bugs where Gmail accepts a malformed message and quietly does the wrong thing rather than returning an error. This version fixes those and adds the tools that were missing:
- Replies actually stay in their thread.
reply_to_emailderives recipients, theRe:subject, and theIn-Reply-To/Referenceschain from the parent message. Passing athreadIdalone now works too — the server backfills the rest. - Drafts with attachments open correctly in the Gmail web UI. The attachment path previously emitted no
Fromheader at all, which Gmail papered over on send but not on drafts. htmlBodyis never silently dropped, and non-ASCII bodies are encoded to match their declared encoding instead of arriving as mojibake.- Deletes are recoverable by default. Trash/untrash for messages and threads; permanent delete is opt-in. Untrash re-adds
INBOX, which Gmail's own untrash does not do. - Per-call account routing — one server instance, every inbox,
accounton every tool. - 56 tests covering MIME construction, threading derivation, header injection, and path security.
Features
- Multiple Account Support - Add, remove, and switch between multiple Gmail accounts
- Default Account Management - Set a default account for quick access
- Send Emails - Plain text, HTML, multipart, with CC/BCC and file attachments
- Search Emails - Use Gmail's powerful search operators (from, subject, has:attachment, newer_than, is:unread, etc.)
- Read Emails - Retrieve full email content with attachment metadata
- Email Modification - Modify labels, mark as read/unread, delete messages
- Batch Operations - Bulk modify labels or delete messages with configurable batch sizes
- Attachment Support - Send attachments and download them with path security validation
- Label Management - Create, update, delete, and list Gmail labels
- Filter Management - Create, list, get, delete filters with pre-built templates
- Correct Thread Replies -
reply_to_emailderives recipients,Re:subject,In-Reply-Toand the fullReferenceschain from the parent message, so replies actually stay in their thread - Full Draft Lifecycle - Create, read, update, send, list, and delete drafts
- Thread Operations - Fetch, label, trash, and restore whole conversations
- Recoverable Deletes - Trash/untrash for messages and threads; permanent delete is opt-in
- Vacation Responder & Aliases - Read and set out-of-office, list send-as identities
- Secure OAuth 2.0 Authentication - No passwords stored; tokens auto-refresh
- Security Hardening - MIME header injection prevention, sensitive path blocking, path traversal protection
- MCP Inspector - Built-in development tool for testing and debugging
Quick Start
-
Setup Google Cloud Console (see detailed steps below):
- Create a project and enable Gmail API
- Create OAuth 2.0 Desktop App credentials
- Configure OAuth consent screen and add test users
- Download credentials as
credentials.json
-
Install and Build:
bun install bun run build -
Add a Gmail account via CLI:
bun src/cli.ts add your-email@gmail.comThis opens your browser for OAuth consent. Tokens are saved in the project's
accounts/directory. -
Configure Claude Desktop (see detailed steps below):
- Add the MCP server entry to
claude_desktop_config.json - Restart Claude Desktop
- Add the MCP server entry to
-
Start Using:
Send an email to john@example.com with subject "Hello" and body "Testing Gmail MCP"
Prerequisites
- Bun (latest version) - Install from bun.sh
- Claude Desktop application installed
- Gmail account with API access enabled
- Google Cloud Console project with Gmail API enabled
Setup Instructions
1. Google Cloud Console Setup
Step 1: Create a Google Cloud Project
- Go to Google Cloud Console
- Click the project dropdown at the top of the page
- Click New Project
- Enter a project name (e.g., "Gmail MCP Server") and click Create
- Make sure the new project is selected in the project dropdown
Step 2: Enable the Gmail API
- In the left sidebar, go to APIs & Services > Library
- Search for Gmail API
- Click on it and click Enable
Step 3: Create OAuth 2.0 Credentials
- In the left sidebar, go to APIs & Services > Credentials
- Click + Create Credentials at the top
- Select Create credentials > choose the Gmail API from the "Select an API" dropdown
- Under "What data will you be accessing?", select User data (not "Application data")
- Click Next
Step 4: Configure the OAuth Consent Screen
When prompted to configure the OAuth consent screen:
- App name: Enter any name (e.g., "Gmail MCP")
- User support email: Select your email from the dropdown
- App logo: Skip this - leave it blank
- Developer contact email: Enter your email address
- Click Save and continue
Step 5: Set Scopes (Optional)
- On the "Scopes" screen, you can skip this - just click Save and continue
- The required scopes are requested at runtime by the MCP server code during the OAuth flow
Step 6: Create the OAuth Client ID
- On the "OAuth Client ID" screen, select Desktop app as the application type
- Enter a name (e.g., "Gmail MCP Desktop Client") or leave the default
- Click Create
Step 7: Download Credentials
- Click the Download button to download the credentials JSON file
- Rename the downloaded file to
credentials.json - Click Done
Step 8: Add Test Users
Since the app has a "Testing" publishing status, only registered test users can authenticate:
- In the left sidebar, go to APIs & Services > OAuth consent screen (this redirects to the Google Auth Platform Audience page)
- Scroll down to the Test users section
- Click + Add users
- Enter the Gmail address(es) you want to use with the MCP server
- You can add multiple test users if you plan to use the multi-account feature
- Click Save
2. Project Setup
-
Clone and Install:
git clone https://github.com/Konadu-Akwasi-Akuoko/gmail-multi-mcp.git cd gmail-multi-mcp bun install -
Build the Project:
bun run build -
Test the Setup (optional but recommended):
bun run inspectThis opens the MCP Inspector for testing tools before connecting to Claude Desktop.
3. Claude Desktop Integration
Step 1: Open Claude Desktop's config directory
The config directory path contains a space (Application Support), so you need to quote or escape it:
macOS:
cd ~/Library/Application\ Support/Claude/
# or
cd "$HOME/Library/Application Support/Claude/"
Note: Tools like
zoxide(z) don't handle spaces in paths well. Use the standardcdcommand with escaping as shown above.
Windows (PowerShell):
cd "$env:APPDATA\Claude\"
Linux:
cd ~/.config/claude/
Step 2: Place your Google credentials
Place the credentials.json file in the project root directory (not Claude Desktop's config directory):
# From wherever you downloaded it
cp ~/Downloads/credentials.json /path/to/gmail-multi-mcp/
Verify it's there:
ls /path/to/gmail-multi-mcp/credentials.json
Step 3: Edit claude_desktop_config.json
Open the config file in your editor:
# macOS
nano ~/Library/Application\ Support/Claude/claude_desktop_config.json
# or with VS Code
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
If the file already has content (like existing preferences), add mcpServers as a sibling key - don't overwrite what's already there. For example, if your file looks like this:
{
"preferences": {
"quickEntryDictationShortcut": "off",
"coworkScheduledTasksEnabled": false,
"sidebarMode": "chat"
}
}
Update it to:
{
"preferences": {
"quickEntryDictationShortcut": "off",
"coworkScheduledTasksEnabled": false,
"sidebarMode": "chat"
},
"mcpServers": {
"gmail": {
"command": "bun",
"args": ["/absolute/path/to/your/gmail-multi-mcp/src/index.ts"]
}
}
}
If the file is empty or doesn't exist, create it with:
{
"mcpServers": {
"gmail": {
"command": "bun",
"args": ["/absolute/path/to/your/gmail-multi-mcp/src/index.ts"]
}
}
}
Important: Replace
/absolute/path/to/your/gmail-multi-mcp/with the actual absolute path to your cloned project. You can get this by runningpwdfrom inside the project directory.
Step 4: Verify bun is accessible
The MCP server uses bun to run. Make sure it's installed and in your PATH:
which bun
# Should output something like: /Users/yourname/.bun/bin/bun
If bun is not found, install it from bun.sh.
Step 5: Restart Claude Desktop
Fully quit Claude Desktop (not just close the window) and reopen it. On macOS, right-click the dock icon and choose Quit, or use Cmd+Q.
After restarting, the Gmail MCP tools should be available in Claude Desktop.
CLI Account Management
The CLI tool manages Gmail accounts separately from the MCP server. This is necessary because the MCP server runs as a background process under Claude Desktop, where a browser OAuth flow can't work.
Why a separate CLI?
When Claude Desktop spawns the MCP server, process.cwd() resolves to Claude Desktop's own directory -- not the project root. The CLI and MCP server both use import.meta.dir to resolve paths relative to the source file, so they always agree on where credentials.json and accounts/ live (the project root).
Commands
# Add a new Gmail account (opens browser for OAuth)
bun src/cli.ts add user@gmail.com
# List all configured accounts
bun src/cli.ts list
# Get or set the default account
bun src/cli.ts default # show current default
bun src/cli.ts default user@gmail.com # set new default
# Re-authenticate an expired token
bun src/cli.ts reauth user@gmail.com
# Remove an account
bun src/cli.ts remove user@gmail.com
# Show the resolved data directory
bun src/cli.ts path
After building
If you've run bun run build, you can also use the compiled binary:
bun build/cli.js list
Environment variable
Set GMAIL_MCP_DATA_DIR to override where the CLI and MCP server look for credentials.json and accounts/:
GMAIL_MCP_DATA_DIR=/custom/path bun src/cli.ts list
First-Time Authentication
Account setup is done via the CLI tool before connecting to Claude Desktop:
- Run
bun src/cli.ts add your-email@gmail.comfrom the project directory - A browser window opens for Google OAuth consent
- Sign in and grant the requested permissions
- Authentication tokens are stored in the
accounts/directory within the project root - Tokens auto-refresh and are valid for 6 months of inactivity
- The MCP server reads these pre-existing tokens at runtime (no browser flow needed)
Available Tools
Email Operations
| Tool | Description |
|---|---|
send_email |
Send emails with HTML, attachments, CC/BCC, and thread reply support |
reply_to_email |
Reply to a message with threading headers derived automatically. Drafts by default; send: true to send |
search_emails |
Search emails using Gmail search operators |
read_email |
Read a specific email by message ID, including Cc and the RFC Message-ID |
Drafts
| Tool | Description |
|---|---|
create_draft |
Create a draft, with attachments and thread-reply support |
get_draft |
Fetch a draft's full content and headers |
update_draft |
Replace a draft's contents (replaces attachments too) |
send_draft |
Send an existing draft by ID |
list_drafts |
List drafts with subject/to/date metadata |
delete_draft |
Delete a draft without sending |
Threads
| Tool | Description |
|---|---|
get_thread |
Fetch every message in a thread with recipients, labels, and Message-IDs. The authoritative way to verify a reply draft |
modify_thread |
Add or remove labels across a whole thread |
trash_thread |
Move a thread to trash |
untrash_thread |
Restore a thread, re-adding INBOX by default |
Email Modification
| Tool | Description |
|---|---|
modify_email |
Add or remove labels on a message |
trash_email |
Move a message to trash (recoverable for 30 days) |
untrash_email |
Restore a message from trash, re-adding INBOX by default |
delete_email |
Permanently delete a message. Requires confirmPermanentDelete: true |
mark_as_read |
Mark a message as read |
mark_as_unread |
Mark a message as unread |
Settings
| Tool | Description |
|---|---|
get_vacation_responder |
Read the current out-of-office configuration |
update_vacation_responder |
Enable/disable the auto-responder, with optional date window |
list_send_as_aliases |
List send-as aliases, signatures, and verification status |
Batch Operations
| Tool | Description |
|---|---|
batch_modify_emails |
Bulk add/remove labels on multiple messages |
batch_delete_emails |
Bulk delete multiple messages |
Attachments
| Tool | Description |
|---|---|
download_attachment |
Download an email attachment to disk |
Label Management
| Tool | Description |
|---|---|
list_email_labels |
List all system and user labels |
create_label |
Create a new label with visibility options |
update_label |
Update a label's name or visibility |
delete_label |
Delete a user-created label |
get_or_create_label |
Get existing label or create if missing |
Filter Management
| Tool | Description |
|---|---|
create_filter |
Create a filter with custom criteria and actions |
list_filters |
List all Gmail filters |
get_filter |
Get details of a specific filter |
delete_filter |
Delete a filter by ID |
create_filter_from_template |
Create from pre-built templates (fromSender, withSubject, withAttachments, largeEmails, containingText, mailingList) |
Account Management
| Tool | Description |
|---|---|
list_accounts |
List all configured Gmail accounts |
add_account |
Add a new Gmail account |
remove_account |
Remove a configured Gmail account |
set_default_account |
Set the default Gmail account |
Development
# Development mode with hot reload
bun run dev
# Test with MCP Inspector
bun run inspect
# Build for production
bun run build
# Type-check without emitting
bun run typecheck
Architecture
Built with TypeScript and follows MCP specifications:
- Entry Point:
src/index.ts- MCP server setup and tool definitions - CLI:
src/cli.ts- Commander.js CLI for terminal-based account management - Gmail Client:
src/gmail-client.ts- Gmail API wrapper (send, search, read, modify, delete, batch ops, attachments) - Account Manager:
src/account-manager.ts- Multi-account credential storage and switching - Email Utils:
src/email-utils.ts- MIME encoding, email validation, path security, Nodemailer integration - Label Manager:
src/label-manager.ts- CRUD operations for Gmail labels - Filter Manager:
src/filter-manager.ts- Gmail filter CRUD and pre-built templates - Authentication:
src/auth.ts- OAuth 2.0 credential management - Types:
src/types.ts- TypeScript interfaces and type definitions
Troubleshooting
Common Issues
"No account specified and no default account set":
- Add an account using the CLI:
bun src/cli.ts add user@gmail.com
"Authentication failed":
- Check if
credentials.jsonexists in the project root (bun src/cli.ts pathshows the resolved directory) - Verify Gmail API is enabled in Google Cloud Console
- Re-authenticate:
bun src/cli.ts reauth user@gmail.com
"Token expired":
- Re-authenticate via CLI:
bun src/cli.ts reauth user@gmail.com
Claude Desktop not detecting MCP server:
- Verify the absolute path in
claude_desktop_config.jsonis correct - Make sure
bunis in your PATH (which bun) - Check that
mcpServersis a top-level key in the config, not nested insidepreferences - Ensure the JSON is valid (no trailing commas, proper bracket matching)
- Restart Claude Desktop fully (Quit + Reopen, not just close the window)
- Check Claude Desktop logs for MCP server errors
zoxide / z can't find the Claude config directory:
- The path contains a space (
Application Support). Usecdwith quotes or backslash escaping instead:cd ~/Library/Application\ Support/Claude/
Development and Testing
Test tools without Claude Desktop:
bun run inspect
Development mode with hot reload:
bun run dev
View server logs:
- Check Claude Desktop logs for MCP server output
- Use Inspector tool for detailed request/response debugging
File Structure
Project Directory:
gmail-multi-mcp/
├── build/ # Compiled JavaScript (auto-generated)
├── accounts/ # Account tokens (auto-generated by CLI)
├── credentials.json # Google OAuth credentials (you provide)
├── src/
│ ├── index.ts # MCP server entry point and tool definitions
│ ├── cli.ts # Commander.js CLI for account management
│ ├── gmail-client.ts # Gmail API wrapper
│ ├── account-manager.ts # Multi-account management
│ ├── email-utils.ts # MIME, validation, security, Nodemailer
│ ├── label-manager.ts # Label CRUD operations
│ ├── filter-manager.ts # Filter CRUD and templates
│ ├── auth.ts # OAuth 2.0 credential management
│ ├── bun.d.ts # Bun-specific type declarations
│ └── types.ts # TypeScript interfaces
├── package.json
└── CLAUDE.md
Claude Desktop Config Directory (only claude_desktop_config.json lives here):
# macOS
~/Library/Application Support/Claude/claude_desktop_config.json
# Linux
~/.config/claude/claude_desktop_config.json
# Windows
%APPDATA%\Claude\claude_desktop_config.json
Security
- Uses minimal required Gmail scopes
- Tokens stored locally with automatic refresh
- No email content stored permanently
- All operations performed locally
- Attachment paths validated against sensitive directories (~/.ssh, ~/.aws, ~/.env, credentials, etc.)
- MIME header injection prevention via CR/LF stripping
- Path traversal protection on attachment downloads
Replying to threads
Gmail accepts a reply whose headers do not match its thread and then quietly files it as a new conversation. There is no error. Three things have to line up: the threadId, a Subject that matches the thread, and an In-Reply-To/References chain built from the parent's RFC Message-ID — not the Gmail hex ID that search_emails returns.
Use reply_to_email and this is handled for you:
reply_to_email(messageId: "18f0a1b2c3d4e5f6", body: "Sounds good.", replyAll: true)
It fetches the parent, derives recipients (dropping your own address), prefixes Re: only if needed, carries the full References chain, and creates a draft by default. Pass send: true to send instead.
If you build a reply by hand with send_email or create_draft, passing threadId alone is now enough — the server backfills the missing headers from the thread's latest message. Passing an explicit inReplyTo always wins.
To verify a reply draft, use get_thread. It returns every message with its recipients, so it will show whether the draft actually landed in the thread and whether Cc is populated. Note that Gmail's compose UI hides Cc behind a toggle, so a correct Cc can look empty until expanded.
Attachments
Attachments are built with Nodemailer and uploaded as base64 in a single request.
- The total is checked against Gmail's 35 MB raw limit before upload, accounting for base64 inflation, so oversized sends fail with a clear message instead of an opaque error.
- Paths are validated against sensitive locations (
~/.ssh,~/.aws,.env,credentials.json, and theaccounts/directory). update_draftreplaces the entire draft, attachments included. Re-pass any attachments you want to keep.
Limitations
- Rate limits: Gmail API has daily quotas
- Token expiry: Tokens expire after 6 months of inactivity
- No resumable upload: attachments must fit in a single 35 MB request
- Gmail only: despite the package name, Calendar/Drive/Docs are not covered
License
MIT
Credits
This server stands on a chain of earlier work. Credit to all of them:
- AlexHramovich/gmail-mcp — the original Gmail MCP server this descends from.
- Konadu-Akwasi-Akuoko/gmail-multi-mcp — the multi-account fork this repository builds directly on.
- GongRzhe/Gmail-MCP-Server — filter templates and batch operation patterns. Archived March 2026.
- shinzo-labs/gmail-mcp — the settings surface (vacation responder, send-as aliases) and full draft lifecycle were modelled on its broader Gmail API coverage.
- taylorwilsdon/google_workspace_mcp — sensitive-path blocking approach for attachment and download safety.
- dmorrill/gmail-mcp-multi — independent confirmation that per-call account routing is the right multi-account shape.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。