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
This repository has not yet undergone a full independent third-party security review end-to-end. The hardening layer (path jails with realpath + O_NOFOLLOW, CRLF sanitization on both email-assembly paths, OAuth scope filtering at startup, Zod bounds on every Gmail ID, crypto MIME boundary, credentials at 0o600, opt-in redacted JSONL audit log with counterparty-PII elision by default (GMAIL_MCP_AUDIT_LOG + GMAIL_MCP_AUDIT_LOG_VERBOSE opt-out), per-bucket daily+monthly write rate limits (send/delete/modify/drafts/labels/filters), LLM-output defense-in-depth fence (<untrusted-tool-output>) with control / zero-width / BiDi-override stripping on every tool response, attachment-filename neutralisation before disk write, protocol-error flagging (isError: true) on tool failures, Sigstore + SLSA + SBOM-signed releases, fast-check fuzz suite) is tested on every CI run. Against the two parent forks, klodr/gmail-mcp is already a meaningful step forward on prompt-injection and supply-chain posture. For mission-critical or high-sensitivity deployments, treat the server as carefully as any third-party MCP: prefer a narrowly-scoped OAuth token, enable human-in-the-loop confirmation on write tools, and track this repo's release notes for security-relevant updates. See SECURITY.md for the detailed threat model.
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.
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) |
❌ | ✅ | |
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 (outdated) | 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 release since the fork diverged | ❌ (consumed as a GitHub install from the intermediate fork) | ✅ dedicated scoped package, signed releases |
| GitHub repo | GongRzhe/Gmail-MCP-Server | ArtyMcLabin/Gmail-MCP-Server | klodr/gmail-mcp |
| Active maintenance (last 30 d) | ❌ (dormant since Aug 2025) | ✅ 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 tsup ESM bundle (smaller tarball, easier to verify) |
❌ (multi-file tsc) |
❌ (multi-file tsc) |
✅ (target node22, ES2024) |
| Testing | |||
| Unit/property tests | ❌ (0 tests) | ✅ (386 tests) | |
Statement coverage across src/** |
0% | 16.14% | >50% |
| 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) |
❌ | ❌ | ✅ |
CONTRIBUTING.md |
❌ | ❌ | ✅ |
.github/FUNDING.yml |
❌ | ❌ | ✅ |
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.
npm install -g @klodr/gmail-mcpOr directly via npx:
npx -y @klodr/gmail-mcpRequires Node.js 22+.
- 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).
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).
{
"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.
| 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| 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, reply_all) 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 (400/6000), delete (200/2000), modify (500/5000), drafts (300/3000), labels (50/500), filters (20/200). The bucket name is lowercase and matches the tool family. Example: GMAIL_MCP_RATE_LIMIT_send=100/day,1500/month. |
| 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, draft_email, 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. |
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 - 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
Every write tool is annotated with destructiveHint / readOnlyHint / idempotentHint per the MCP spec so policy-aware clients can gate on HITL confirmation.
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:alice@example.com after:2026/01/01 has:attachment. Full reference: Google's Gmail search operators cheat sheet.
See ROADMAP.md.
The wider Gmail-MCP landscape — 29 standalone repositories and 323 forks of the original GongRzhe server — is reviewed in docs/COMPETITORS.md. That page covers which ideas we borrowed, which we chose not to, and where klodr/gmail-mcp sits on the maturity axes.
See CONTRIBUTING.md for the test / build / lint checklist and release process.
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.
See CONTINUITY.md for the handover plan if the maintainer becomes unavailable.
MIT — see LICENSE.
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.