Gmail Manager MCP Server
Gmail MCP server (33 tools) with optional recipient allowlist and local audit log
Documentation
mcp-gmail-manager
A comprehensive Gmail Model Context Protocol server: 33 tools covering send, reply, forward, drafts, search, read, attachments, trash, labels, filters, signature, and vacation responder.
Two optional features that distinguish it from other Gmail MCPs:
- Local audit log (on by default) β every write/send/modify/download appends a JSON line to
audit.jsonl. Metadata only (no body content). Compliance trail without third-party services. - Recipient allowlist (off by default) β when enabled, every outbound operation (
send_email,create_draft,reply_to_message,forward_message) checks recipients against configured domains and explicit addresses. Useful for institutional / compliance contexts. Seeexamples/config.with-allowlist.jsonto enable.
Tools (33)
| Group | Tools |
|---|---|
| Send / reply / forward | send_email, reply_to_message, forward_message |
| Drafts | create_draft, list_drafts, send_draft, update_draft, delete_draft |
| Read / profile | get_profile, get_message, search_threads, get_thread |
| Attachments | get_message_attachments, download_attachment |
| Trash | trash_message, untrash_message, trash_thread, untrash_thread |
| Labels | list_labels, create_label, update_label, delete_label, label_message, unlabel_message, label_thread, unlabel_thread |
| Filters | list_filters, create_filter, delete_filter |
| Signature | get_signature, update_signature |
| Vacation responder | get_vacation_responder, set_vacation_responder |
OAuth scopes requested: gmail.modify + gmail.settings.basic. Does not request the https://mail.google.com/ superuser scope β permanent delete is intentionally unsupported.
Requirements
- Python β₯ 3.10
- A Google Cloud project with the Gmail API enabled and an OAuth 2.0 client (Desktop type)
- A way to forward
localhost:8765to your auth host (typicallyssh -L 8765:localhost:8765 user@host)
Install
Recommended β pipx (installs in an isolated venv, exposes the entry points on $PATH):
pipx install mcp-gmail-manager
If pipx is missing:
sudo apt install pipx # Debian / Ubuntu / Mint
brew install pipx # macOS
pipx ensurepath # makes ~/.local/bin available, may need shell restart
Alternative β manual venv:
python3 -m venv ~/.venv-mcp-gmail
~/.venv-mcp-gmail/bin/pip install mcp-gmail-manager
# Use the absolute path when registering with Claude Code (see below)
Why not plain pip install system-wide? On modern Debian-based distros it fails with error: externally-managed-environment (PEP 668) β the OS protects its Python. The two methods above are the canonical workarounds.
From source:
git clone https://github.com/arthjhon/mcp-gmail-manager.git
cd mcp-gmail-manager
pipx install .
Google Cloud setup (one-time, ~10 minutes)
- Go to Google Cloud Console and create a new project (or pick an existing one).
- Enable the Gmail API (not "Gmail MCP API" β that's Google's own remote MCP; not what we want).
- Configure the OAuth consent screen:
- User type: Internal if your account is part of a Google Workspace (no token expiration); otherwise External in Testing mode (up to 100 users, refresh tokens expire every 7 days β see Token expiration below).
- Scopes: add
https://www.googleapis.com/auth/gmail.modifyandhttps://www.googleapis.com/auth/gmail.settings.basic. Do not add anything else. - Test users (External only): add the Gmail address you'll authenticate with.
- Create an OAuth Client ID:
- Application type: Desktop app
- Download the JSON. Save it as
credentials.json.
First-time auth
Move your credentials into the config directory (default ~/.config/mcp-gmail-manager/):
mkdir -p ~/.config/mcp-gmail-manager
mv ~/Downloads/client_secret_*.json ~/.config/mcp-gmail-manager/credentials.json
chmod 600 ~/.config/mcp-gmail-manager/credentials.json
Run the auth flow:
mcp-gmail-manager-auth
This binds to localhost:8765 and prints a Google authorisation URL. Open it in a browser on a machine that can reach localhost:8765 on the auth host:
- Local desktop: the printed URL works directly.
- Remote / headless server: forward the port from your laptop first:
Then runssh -L 8765:localhost:8765 user@your-servermcp-gmail-manager-authinside that SSH session.
Authorise with the Google account that will own outbound mail. On success the script writes token.json and exits.
Token expiration
The refresh token's lifetime depends on how the OAuth consent screen is configured:
| Setup | Refresh token lifetime | Re-auth required? |
|---|---|---|
| Internal (Google Workspace) | No expiration | Never (until user revokes) |
| External + Testing | 7 days (Google's policy for unverified apps) | Yes β weekly |
| External + Production verified | No expiration | Never, but verification requires a paid Google security assessment |
When the refresh token expires in Testing mode you'll see invalid_grant or Token has been expired or revoked errors. To recover:
rm ~/.config/mcp-gmail-manager/token.json
mcp-gmail-manager-auth
Takes ~30 seconds. Your credentials.json is not affected β only the user's token.
How to avoid the weekly rotation
- Workspace users: configure the consent screen as Internal instead of External. Token never expires.
- Personal Gmail users: weekly re-auth is the only practical option today. Production verification for
gmail.modifyrequires a Google security assessment (paid, weeks of process) β not feasible for most personal projects. - Set a calendar reminder or a cron job to nudge you weekly. A future release may add proactive in-tool warnings before expiry.
Register with Claude Code
If installed via pipx:
claude mcp add gmail-manager -- mcp-gmail-manager
If installed in a manual venv that isn't on $PATH:
claude mcp add gmail-manager -- ~/.venv-mcp-gmail/bin/mcp-gmail-manager
Restart your Claude Code session so the new tool schemas load.
Configuration
~/.config/mcp-gmail-manager/config.json is optional β if it doesn't exist, sensible defaults apply (no allowlist, audit log enabled). Two ready-to-copy examples are provided:
examples/config.example.jsonβ minimal, no allowlist (default behaviour). Use this if you want the MCP to send to any address.examples/config.with-allowlist.jsonβ institutional setup with allowlist enforced.
Schema reference:
{
"allowlist": {
"enabled": false,
"domains": [],
"emails": []
},
"audit_log": {
"enabled": true,
"path": null
},
"attachments": {
"max_total_bytes": 20971520
}
}
| Field | Default | Meaning |
|---|---|---|
allowlist.enabled | false | When false, any recipient is accepted. Enable explicitly for institutional use. |
allowlist.domains | [] | Lower-case domain suffixes accepted as recipients. |
allowlist.emails | [] | Explicit lower-case email addresses accepted regardless of domain. |
audit_log.enabled | true | Append every write/modify/send to JSONL. |
audit_log.path | null | null β <config_dir>/audit.jsonl. Override to centralise logs. |
attachments.max_total_bytes | 20971520 (20 MB) | Combined size cap per send. Gmail's hard limit is 25 MB raw. |
Environment variable overrides
| Variable | Default |
|---|---|
GMAIL_MCP_CONFIG_DIR | $XDG_CONFIG_HOME/mcp-gmail-manager or ~/.config/mcp-gmail-manager |
GMAIL_MCP_CREDENTIALS | <config_dir>/credentials.json |
GMAIL_MCP_TOKEN | <config_dir>/token.json |
Security notes
- Token storage:
token.jsonis writtenchmod 600. Treat it as a password β anyone with read access can act as your Gmail account. - No remote attestation: this server runs entirely on your machine. No telemetry, no third-party calls beyond
googleapis.com. - Allowlist is defence in depth, not perimeter security: an attacker who compromises your machine can read
token.jsonand call the Gmail API directly, bypassing the MCP entirely. The allowlist defends against the LLM being tricked or hallucinating malicious recipients, not against host compromise. - OAuth scope is broad:
gmail.modifycovers everything except permanent delete. If you only need to send, fork and replace the scope withgmail.send. - Permanent delete intentionally unsupported: we don't request
https://mail.google.com/. Deletes go to Trash and can be undone withuntrash_*.
Limitations
- OAuth "Production" verification for
gmail.modifyrequires a paid Google security assessment. Stay in "Internal" (Workspace, no expiration) or "Testing" (β€ 100 users, 7-day refresh token rotation β see Token expiration) to avoid this. - HTML email body composition is not exposed as a first-class field. Send via
create_draft+ manual HTML editing in the Gmail UI, or extend_build_mimein a fork. - Push notifications (Pub/Sub
watch/stop) not implemented β out of scope.
Contributing
Issues and PRs welcome. Keep changes scoped, document any new tool with a schema example, and add an audit-log entry for anything that mutates state.
License
MIT β see LICENSE.