@klodr/gmail-mcp
v1.1.5
Published
Gmail MCP server — scope-gated tools + attachment/download path jails + supply-chain hardening. Fork of GongRzhe/Gmail-MCP-Server via ArtyMcLabin's intermediate fork.
Maintainers
Readme
📧 gmail-mcp
Read, search, send, draft, label, filter, and thread Gmail from any MCP-enabled AI assistant. Wraps the Gmail API with scope-gated tools and in-process safeguards.
[!NOTE] Hardened + enhanced fork of GongRzhe/Gmail-MCP-Server (archived 2026-03-03), via ArtyMcLabin/Gmail-MCP-Server. Since the divergence point: 130+ commits and an extensive rewrite — security hardening, Gmail-surface improvements (reply-all, send-as alias, thread-level tools, download-to-disk, recipient pairing, batch ops with retry…), supply-chain hygiene, and CI gating. Every PR goes through CodeRabbit + dual-model Qodo Merge before merge. See SECURITY.md for the controls and threat model, and the comparison table below for the parent-forks delta.
A Model Context Protocol (MCP) server that lets AI assistants (Claude Desktop, Claude Code, Cursor, Continue, OpenClaw…) read and manage a Gmail account through scope-gated tools. Exposes the Gmail v1 API surface you actually need (messages, threads, labels, filters, attachments, drafts, reply-all) behind a single npx install.
✨ Why this MCP?
Comparison of the three maintained forks of the original Gmail MCP server, focusing on what an agent platform actually needs — prompt-injection safety, supply-chain integrity, and operational hygiene:
| Capability | GongRzhe/Gmail-MCP-Server (original, unmaintained) | ArtyMcLabin/Gmail-MCP-Server (intermediate fork) | klodr/gmail-mcp (this repo) |
|---|:---:|:---:|:---:|
| Core Gmail surface | | | |
| Send / draft / read / search messages | ✅ | ✅ | ✅ |
| Label CRUD | ✅ | ✅ | ✅ |
| Filter CRUD | ⚠️ list_filters broken | ✅ fixed | ✅ |
| Batch modify / delete | ✅ | ✅ | ✅ |
| Reply threading (In-Reply-To / References) | ❌ orphaned replies | ✅ | ✅ |
| Reply-all tool | ❌ | ✅ | ✅ |
| Send-as alias (from parameter) | ❌ | ✅ | ✅ |
| Thread-level tools (get_thread, list_inbox_threads, get_inbox_with_threads) | ❌ | ✅ | ✅ |
| Download email to disk (json/eml/txt/html) | ❌ | ✅ | ✅ |
| Download attachment | ✅ | ✅ | ✅ |
| OAuth / authorization | | | |
| --scopes flag for least-privilege auth | ❌ | ✅ | ✅ |
| Tool list filtered by granted scopes | ❌ | ✅ | ✅ |
| OAuth credentials file mode 0o600 | ❌ | ✅ | ✅ |
| Security — input handling | | | |
| CRLF header injection sanitization (\r\n\0) | ❌ | ⚠️ partial | ✅ |
| Path traversal in download_attachment | ❌ | ✅ fixed | ✅ |
| Attachment source jail (GMAIL_MCP_ATTACHMENT_DIR) blocks exfiltration of ~/.ssh/id_rsa etc. via prompt injection | ❌ | ❌ | ✅ |
| Download destination jail (GMAIL_MCP_DOWNLOAD_DIR) | ❌ | ❌ | ✅ |
| O_NOFOLLOW on leaf writes (pre-existing symlink at destination rejected) | ❌ | ❌ | ✅ |
| Post-mkdir realpath re-verification (TOCTOU defense) | ❌ | ❌ | ✅ |
| Zod bounds on maxResults / batchSize / messageIds length | ❌ | ❌ | ✅ |
| Cryptographic MIME boundary (crypto.randomBytes, not Math.random) | ❌ | ❌ | ✅ |
| MCP protocol & tool surface | | | |
| MCP SDK version | v0.4.x | v1.27.x | v1.29.x |
| Tool annotations (readOnlyHint / destructiveHint / idempotentHint) | ❌ | ✅ | ✅ |
| llms-install.md (LLM-readable install guide) | ❌ | ❌ | ✅ |
| Publishing / discoverability | | | |
| Published on npm | ❌ stale — no future releases (repo archived) | ❌ (consumed as a GitHub install from the intermediate fork) | ✅ dedicated scoped package, signed releases |
| Active maintenance (last 30 d) | ❌ (archived 2026-03-03) | ⚠️ sporadic | ✅ daily review cycle (CodeRabbit + human) |
| Supply-chain integrity | | | |
| Node.js floor | ❌ >=14 (EOL April 2023) | ❌ >=14 (EOL April 2023) | ✅ >=22 (Active LTS, maintenance until 2027-04-30) |
| CI: CodeQL Advanced (javascript-typescript + actions) | ❌ | ❌ | ✅ |
| CI: OpenSSF Scorecard (weekly scan + badge) | ❌ | ❌ | ✅ |
| CI: Socket Security supply-chain alerts | ❌ | ❌ | ✅ |
| CI: CodeRabbit assertive reviews on every PR | ❌ | ❌ | ✅ |
| Release: Sigstore-signed dist/index.js + SLSA in-toto attestation | ❌ | ❌ | ✅ |
| Release: npm provenance statement | ❌ | ❌ | ✅ |
| Release: single-file ESM bundle | ❌ | ❌ | ✅ |
| Testing | | | |
| Unit/property tests | ❌ (0 tests) | ⚠️ (97 tests) | ✅ (631 tests) |
| Statement coverage across src/** | 0% | 16.14% | >97% |
| Fast-check property-based fuzz suite | ❌ | ❌ | ✅ |
| Hardening-specific test file (jails, CRLF, O_EXCL) | ❌ | ❌ | ✅ |
| CI/CD hardening | | | |
| Shell-injection-safe GitHub Actions workflows | ❌ | ✅ | ✅ |
| Workflows use least-privilege permissions: scopes | ❌ | ✅ | ✅ |
| All GitHub Actions pinned by full commit SHA | ❌ | ❌ | ✅ |
| Operational | | | |
| CHANGELOG.md (Keep-a-Changelog) | ❌ | ❌ | ✅ |
| SECURITY.md (vulnerability reporting) | ❌ | ❌ | ✅ |
klodr/gmail-mcp is the only one of the three with (a) source-path jails that make prompt-injection attachment exfiltration inert, (b) a modern supply chain (Scorecard, Socket, Sigstore), and (c) an in-repo review policy (.coderabbit.yaml) that every PR must pass before merge.
📦 Installation
npm install -g @klodr/gmail-mcpOr directly via npx:
npx -y @klodr/gmail-mcpRequires Node.js 22+.
⚙️ Configuration
1️⃣ Google Cloud OAuth credentials
- Open the Google Cloud Console.
- Create a project and enable the Gmail API.
- Under APIs & Services → Credentials, create an OAuth 2.0 Client ID (Desktop or Web). For Web, add
http://localhost:3000/oauth2callbackto the authorised redirect URIs. - Download the JSON, rename it to
gcp-oauth.keys.json, place it at~/.gmail-mcp/gcp-oauth.keys.json(or override withGMAIL_OAUTH_PATH=/abs/path/gcp-oauth.keys.json).
2️⃣ Authenticate (once)
npx -y @klodr/gmail-mcp auth --scopes=gmail.readonlyAlways pass --scopes with the minimum you actually need — the MCP filters the tool list at startup based on the granted scopes, so a read-only token doesn't expose write tools to the LLM. A browser opens for Google's consent flow; tokens are written to ~/.gmail-mcp/credentials.json (mode 0o600).
3️⃣ Register the server with your MCP client
{
"mcpServers": {
"gmail": {
"command": "npx",
"args": ["-y", "@klodr/gmail-mcp"]
}
}
}Client-specific config file:
- Claude Code:
~/.claude.json - Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) /%APPDATA%\Claude\claude_desktop_config.json(Windows) - Cursor:
~/.cursor/mcp.json - OpenClaw:
~/.openclaw/openclaw.json
See llms-install.md for an LLM-readable install guide.
🔑 OAuth scopes
| Scope shorthand | Full Gmail scope | What it grants |
|---|---|---|
| gmail.readonly | …/auth/gmail.readonly | Read messages, threads, labels (filter tools require gmail.settings.basic) |
| gmail.modify | …/auth/gmail.modify | Readonly + apply/remove labels, delete messages |
| gmail.compose | …/auth/gmail.compose | Create drafts |
| gmail.send | …/auth/gmail.send | Send messages |
| gmail.labels | …/auth/gmail.labels | Manage labels only |
| gmail.settings.basic | …/auth/gmail.settings.basic | Manage filters |
Recipes:
# Read-only browsing
npx @klodr/gmail-mcp auth --scopes=gmail.readonly
# Read + send (mailing-list bot)
npx @klodr/gmail-mcp auth --scopes=gmail.readonly,gmail.send
# Everything (default; explicit)
npx @klodr/gmail-mcp auth --scopes=gmail.modify,gmail.settings.basic
# Default + permanent delete (delete_email / batch_delete_emails)
# gmail.modify authorizes trash; mail.google.com is the only scope
# that authorizes purging from Trash. Both are listed because the
# tool gate does exact scope-name matching — a token holding only
# mail.google.com would not enable the gmail.modify-gated tools,
# even though Google's scope hierarchy would technically accept the
# same calls.
npx @klodr/gmail-mcp auth --scopes=gmail.modify,mail.google.com,gmail.settings.basic🛡️ Safeguards
| Knob | Env var | Default | Notes |
|---|---|---|---|
| Attachment jail | GMAIL_MCP_ATTACHMENT_DIR=/abs/path | ~/GmailAttachments/ (auto-created mode 0o700) | Every attachment path (send_email, draft_email, update_draft, reply_all, reply_to_email, forward_email) must live inside this directory after realpath canonicalization. Symlinks pointing outside are rejected. Blocks prompt-injected exfiltration of ~/.ssh/id_rsa, ~/.gmail-mcp/credentials.json, ~/.claude.json, etc. |
| Download jail | GMAIL_MCP_DOWNLOAD_DIR=/abs/path | ~/GmailDownloads/ (auto-created mode 0o700) | download_email and download_attachment write exclusively here. The leaf is opened with O_NOFOLLOW; post-mkdir the resolved path is re-verified against the jail root (TOCTOU defense). |
| OAuth keys path | GMAIL_OAUTH_PATH=/abs/path/gcp-oauth.keys.json | ~/.gmail-mcp/gcp-oauth.keys.json | Google Desktop/Web OAuth client credentials. |
| Credentials path | GMAIL_CREDENTIALS_PATH=/abs/path/credentials.json | ~/.gmail-mcp/credentials.json | Access/refresh tokens. File mode 0o600. |
| Rate limit state dir | GMAIL_MCP_STATE_DIR=/abs/path | ~/.gmail-mcp/ | Where the rolling call-history for rate limiting is persisted (ratelimit.json, mode 0o600). Same directory is reused for any future state files. |
| Rate limit overrides | GMAIL_MCP_RATE_LIMIT_<bucket>=D/day,M/month | see below | Override the per-bucket daily/monthly caps. Buckets: send (100/2000), delete (200/2000), modify (500/5000), drafts (300/3000), labels (50/500), filters (20/200). The send cap is sized at the upper end of a human professional workload (~40 emails/day with a 2.5× cushion); raise it via GMAIL_MCP_RATE_LIMIT_send=400/day,6000/month if you need the pre-v0.30.2 default. The bucket name is lowercase and matches the tool family. |
| Rate limit disable | GMAIL_MCP_RATE_LIMIT_DISABLE=true | unset (limiter active) | Kill-switch for the entire limiter. Use only for test suites or controlled batch operations. |
| Audit log | GMAIL_MCP_AUDIT_LOG=/abs/path/audit.jsonl | unset (no audit trail) | Opt-in append-only JSONL log of every tool call (name, redacted args, outcome). File mode 0o600. Must be an absolute path; relative paths are rejected at startup. Redaction keeps structural keys and drops values under an allowlist. |
| Dry-run | GMAIL_MCP_DRY_RUN=true | unset (real calls) | When "true" (strict match), every write tool (send_email, reply_all, reply_to_email, forward_email, draft_email, update_draft, delete_draft, send_draft, delete_email, modify_email, batch_modify_emails, batch_delete_emails, create_label, update_label, delete_label, get_or_create_label, create_filter, delete_filter, create_filter_from_template, modify_thread) short-circuits before reaching Gmail and returns the redacted payload it would have sent. Useful for CI smoke tests, agent debugging, and human-in-the-loop approval flows. Read tools ignore the flag (nothing to preview). Matches MERCURY_MCP_DRY_RUN / FAXDROP_MCP_DRY_RUN on the sibling servers. |
🛠️ Tools
The exact set depends on the OAuth scopes granted at auth time. Full catalog:
- Messages —
send_email,draft_email,read_email,search_emails,modify_email,delete_email,download_email,download_attachment,batch_modify_emails,batch_delete_emails,reply_all,reply_to_email,forward_email - Drafts —
list_drafts,get_draft,update_draft,delete_draft,send_draft(fullusers.drafts.*surface;draft_emailabove creates the initial draft) - Threads —
get_thread,list_inbox_threads,get_inbox_with_threads,modify_thread - Labels —
list_email_labels,create_label,update_label,delete_label,get_or_create_label - Filters —
list_filters,get_filter,create_filter,delete_filter,create_filter_from_template - Recipient pairing —
pair_recipient(manage the~/.gmail-mcp/paired.jsonallowlist whenGMAIL_MCP_RECIPIENT_PAIRING=true)
Every write tool is annotated with destructiveHint / readOnlyHint / idempotentHint per the MCP spec so policy-aware clients can gate on HITL confirmation.
🔍 search_emails query syntax
search_emails accepts Gmail's native search operators — from:, to:, subject:, has:attachment, after:YYYY/MM/DD, before:YYYY/MM/DD, is:unread, label:<name>, etc. They combine freely: from:[email protected] after:2026/01/01 has:attachment. Full reference: Google's Gmail search operators cheat sheet.
🗺️ Roadmap
See ROADMAP.md.
🌐 Ecosystem
Other MCP servers in the klodr family
- 📧 klodr/gmail-mcp — Gmail (you are here)
- 📠 klodr/faxdrop-mcp — Send real faxes via FaxDrop
- 🏦 klodr/mercury-invoicing-mcp — Mercury banking + invoicing
Wider Gmail-MCP landscape
29 standalone repositories and 349 forks of the original GongRzhe server are reviewed in docs/COMPETITORS.md — which ideas we borrowed, which we chose not to, and where klodr/gmail-mcp sits on the maturity axes.
🤝 Contributing
See CONTRIBUTING.md for the test / build / lint checklist and release process.
🔒 Security
See SECURITY.md for the vulnerability-reporting process and the current security model, and ASSURANCE_CASE.md for the threat model, trust boundaries, and CWE/OWASP mitigation table.
📋 Project continuity
See CONTINUITY.md for the handover plan if the maintainer becomes unavailable.
📄 License
MIT — see LICENSE.
📜 History
klodr/gmail-mcp is the maintenance fork of a two-step upstream chain:
- GongRzhe/Gmail-MCP-Server — the original server. Unmaintained since August 2025 (7+ months with zero maintainer activity and 72+ unmerged pull requests).
- ArtyMcLabin/Gmail-MCP-Server — Arty MacKiewicz's active fork, which merged a pile of long-pending community PRs: reply threading (#91), reply-all (#3 by @MaxGhenis),
list_filtersfix (#4 by @nicholas-anthony-ai),--scopesflag (#6 by @tansanDOTeth), CI/CD hardening (#9) + security hardening (#10) + dependency CVE fixes (#11) by @JF10R, tool annotations (#14 by @bryankthompson),download_email(#13 by @icanhasjonas).
klodr/gmail-mcp carries all of the above forward and adds the supply-chain / path-jail / review-policy layer (see comparison table above). Credit to every PR author along the chain.
