gmail-mcp
Provides integration with Gmail, allowing agents to send, reply to, forward, draft, search, read, and organize emails, manage labels and attachments, and support multiple Gmail accounts via OAuth.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@gmail-mcpSearch my inbox for unread emails from my boss"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pigeon-mcp
Gmail connector for MCP clients. One server, many Gmail accounts via OAuth refresh tokens. Sends real MIME (file-path attachments, live signatures, post-send proof). Reads and organises mail without dumping megabytes of base64 into the model.
Not a wrapper around Google's hosted Gmail MCP — this builds RFC822 on the host and talks to gmail.googleapis.com directly.
Scope today: Gmail only. The Google Cloud project may also have Calendar and Drive APIs enabled for later work — this server does not call them yet. Do not request Calendar/Drive OAuth scopes until those tools ship.
Features
Multi-account OAuth — add mailboxes with
accounts_add; tokens stored asgmail-token-*.json(mode 0640)Many identities on one mailbox —
identities_listreads Gmail's verified send-as list;from_identityon send/reply/forward/draft setsFrom,Reply-Toand the alias's own signature, validated in the handler. Seedocs/mailroom.mdRouting headers — every read exposes
originalTo(X-Gm-Original-To),deliveredTo,replyTo,authResults;messages_listsweeps headers without bodiesSend / reply / forward — server-built MIME, outbox file paths only, 25 MB cap, idempotency keys, proof on success
Read / organise — search (threads + pagination), get thread/message, labels, archive/trash, drafts
Attachments — send from configured outbox root (default
~/Outbox); stage viaPOST /outbox/stage(bearer); download to configured download root (default~/Inbox)Dual transport — stdio for local harnesses; Streamable HTTP behind a gateway for remote clients
Related MCP server: Gmail MCP Server
Requirements
Python 3.12+ (development uses 3.13 via pyenv)
A Google Cloud Web application OAuth client with redirect
https://<your-host>/oauth/callbackA Linux or macOS host you control, behind TLS (nginx / Caddy / Cloudflare)
Quick start
git clone https://github.com/iXanadu/pigeon-mcp.git
cd pigeon-mcp
# Python 3.12+ (example with pyenv)
pyenv virtualenv 3.13 pigeon-mcp-3.13
pyenv local pigeon-mcp-3.13
pip install -e '.[dev]'
# Config (see examples/)
cp examples/config.example .env
cp examples/secrets.example .keys
chmod 600 .keys
# Sanity check
pigeon-doctorFill in .keys with the Web client id/secret and a long random PIGEON_MCP_HTTP_BEARER_TOKEN. Set PIGEON_MCP_OAUTH_PUBLIC_REDIRECT_URI in .env to your public callback.
Google Cloud Console (one-time)
Step | Where | What |
1 | APIs & Services → Library | Enable Gmail API |
2 | OAuth consent screen | External → Publish app (In production). Do not stay in Testing (7-day refresh expiry). See the doc for Workspace Internal. |
3 | Credentials → Create | OAuth client ID → Web application |
4 | Web client | Redirect |
5 |
| Web client id/secret → |
Full guide (scopes, the unverified-app warning, Workspace vs personal Gmail, the 7-day Testing trap, token protection, legal URLs): docs/google-oauth-setup.md. Privacy / Terms URLs for the consent screen: docs/legal/.
Scopes are fixed in the server: gmail.modify + gmail.send — read/send/organise mail; modify also reads the send-as list (identities, live signature, not cached). No username/password, app password, or pasted refresh token in chat.
Connect a mailbox
The agent calls accounts_auth_start over HTTP and gets an auth_url. A human opens it on their own computer (any browser, anywhere — passkeys stay local), picks the Google account, clicks Allow. Google redirects to the public /oauth/callback, the server stores the token, and the address shows up in accounts_list. That address is the account argument for every other tool.
This works on a headless server with no tunnel and no token copying — the callback is a public HTTPS URL, not a loopback. Empty accounts_list on a fresh host is success, not a fault.
Tokens land in PIGEON_MCP_TOKENS_DIR (default ~/.config/pigeon-mcp/tokens/) as gmail-token-<account>.json (mode 0640). On a production host, point it at a directory your backup sweeps.
If you run pigeon purely on your own machine over stdio and never expose HTTP, you can add a Google Desktop OAuth client (redirect http://127.0.0.1:8767/oauth/callback) to .keys as PIGEON_MCP_GOOGLE_CLIENT_ID / _SECRET and use accounts_add, which opens a local browser. accounts_add / accounts_remove exist only on the stdio transport. Most deployments do not need this.
Deployment layout
┌──────────────────────┐ ┌──────────────────────────────┐
│ Any browser │ │ Your server (Linux/macOS) │
│ (human clicks Allow)│──────► │ TLS proxy ─► pigeon-mcp-http │
│ │ /oauth │ 127.0.0.1:8879 + .env/.keys │
└──────────────────────┘callback└──────────────┬───────────────┘
│ /mcp /outbox/stage
agent seat (bearer)pigeon-mcp-httpbinds loopback (127.0.0.1:8879); the proxy terminates TLS and forwards/mcp,/outbox/stage,/oauth/callback,/healthz.The bearer is transport auth: the proxy or the agent presents
Authorization: Bearer …on/mcpand/outbox/stage./oauth/callbackis public by necessity (a browser redirect carries no bearer); it is protected by single-usestate+ PKCE and only a bearer-authenticated caller can start a flow.If you put an access gate (e.g. Cloudflare Access) in front of the host, exempt
/oauth/callbackor consent dies after the user clicks Allow.In-repo deploy kit for the reference host:
deploy/DEPLOYING.md.
After deploy: pigeon-doctor, start the service (systemd on Linux, ./scripts/start.sh LaunchAgent on macOS), then accounts_list over HTTP.
Configuration
Non-sensitive settings live in .env; secrets in .keys (never commit either when populated). Templates: examples/config.example and examples/secrets.example.
Variable | File | Purpose |
|
| Label for logs/status |
|
| Server log level |
|
| HTTP bind address (default |
|
| HTTP port (default |
|
| Send/stage attachment paths (pick per machine; |
|
|
|
|
| OAuth token storage directory |
|
| Public HTTPS callback — must match the Web client exactly |
|
| Google Web OAuth client id |
|
| Google Web OAuth client secret |
|
| Bearer token for HTTP transport |
|
| Optional, stdio only: loopback callback for a Desktop client |
|
| Optional, stdio only: Desktop client for local |
Run pigeon-doctor after changing config.
Transports
stdio (local harness)
pigeon-mcpSame tools as HTTP plus accounts_add / accounts_remove (local Desktop-client consent). Wire into Cursor / Claude Code MCP config with the venv pigeon-mcp binary and cwd set to the repo (so .env / .keys load).
Streamable HTTP (gateway)
pigeon-mcp-httpBinds 127.0.0.1:8879 by default. Requires Authorization: Bearer <PIGEON_MCP_HTTP_BEARER_TOKEN>; requests without a valid token get 401. The bearer is the whole transport auth — there is no OAuth authorization server for MCP clients, and /.well-known/oauth-* 404s are intentional.
HTTP allow-list: read/organise tools plus send, reply, forward, draft_create, draft_send, identities_list, messages_list, accounts_list, accounts_auth_start, and gmail_status. accounts_add / accounts_remove stay on stdio.
Stage attachments (no scp required):
curl -sS -X POST "https://pigeon.c52.com/outbox/stage?filename=deed.pdf" \
-H "Authorization: Bearer $PIGEON_MCP_HTTP_BEARER_TOKEN" \
--data-binary @deed.pdf
# → {"path":".../deed.pdf","filename":"deed.pdf","size":N,...}Then call send / reply / forward with attachments_json using that path. Proxy must expose /outbox/stage (same bearer as /mcp). Cap: 25 MB.
macOS service (user LaunchAgent)
./scripts/start.sh # install plist → ~/Library/LaunchAgents, load
./scripts/stop.sh
./scripts/restart.shEdit launchd/com.pigeon-mcp.plist paths if your checkout or pyenv name differs. Logs go to logs/.
On Linux, run pigeon-mcp-http under systemd with the same loopback bind — see Deployment layout above.
Tools
Tool | Notes |
| Version and config summary |
| Connected addresses and token health |
| Start Google consent over HTTP; returns |
| Local Desktop-client consent (stdio only, optional) |
| Revoke and drop token (stdio only) |
| Verified send-as identities for an account — the only values |
| Gmail query; returns threads |
| Gmail query; returns messages with headers + snippet, no bodies (routing sweeps) |
|
|
| Writes under download root |
| Paths only; rejects |
| Same attach/proof rules as send; |
| User + system labels |
| Comma-separated names or ids |
| Thread-level |
Every tool except accounts_list, accounts_add, and gmail_status requires an account argument (the Gmail address).
Send rules (summary)
send/reply/forward/draft_sendrequire a uniqueidempotency_key; a replay with the same key returns the first result and sends nothingStage remote files first:
POST /outbox/stage(bearer) → use returnedpathAttachments:
{ "path": "/absolute/or/under/outbox/file.pdf" }— no inline base64from_identity(optional): a verified send-as address on the account — setsFromwith display name andReply-To; rejected in the handler if not inidentities_listLive Gmail signature of the sending identity appended at send time (not cached)
Optional
footerafter signatureReturns proof: sizes, hrefs,
okfalse → tool error (e.g. chopped attachment orgoogle.com/urlrewrite)
Tests
pytest tests/ -vUses mocked Gmail HTTP; no live mailbox required.
Mailroom: one mailbox, many agents
Give each agent its own address on one mailbox (Workspace catch-all + send-as, or consumer plus-addressing), route inbound on originalTo → deliveredTo → to, trust only recipients in identities_list, send with from_identity. Full pattern, setup steps, DKIM/alias tiers, label scheme and the do-not-attempt list: docs/mailroom.md.
Docs
Doc | For whom | What |
The agent seat (GrokBot, OpenClaw, Hermes, …) | Connect card, OAuth gotchas, send-with-file, rules of the road, do-not-attempt, escalation — paste into the seat's context | |
Operator + agent | One mailbox, many identities: setup, dispatch, trust tiers, labels, DKIM | |
Operator | Consent screen, scopes, Testing trap, unverified-app warning | |
Operator with no server yet | The $5 VPS on-ramp: ten minutes by hand, four prompts for the rest | |
Operator | How the reference host ships: pull, install, restart, verify, auto-rollback | |
Operator | Privacy / Terms for the consent screen | |
Contributors | Acceptance criteria |
Same content lives on the reference site (pigeon.c52.com) as pages; the repo is the source of truth.
Spec
Product requirements: docs/specs/gmail-mcp-spec.md
License
Apache-2.0
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
A MCP server for Gmail that lets you search, read, and draft emails and replies.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables interaction with Gmail through MCP-compatible clients to list, read, search, and send emails. It supports advanced features such as managing labels, handling threaded replies, and utilizing Gmail's native search syntax.492MIT
- AlicenseAqualityDmaintenanceProvides access to Gmail functionalities including listing unread emails, searching via query syntax, and managing messages through archiving or marking as read. It enables MCP clients to securely interact with and organize email data using the Gmail API.5MIT
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Gmail through the MCP protocol, supporting sending, reading, searching, replying, forwarding, managing drafts and labels, and saving attachments.153MIT
- FlicenseNot gradedqualityCmaintenanceEnables interacting with multiple Gmail accounts through a single MCP server, supporting search, labels, drafts, and thread management with per-account OAuth.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/iXanadu/pigeon-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server