gmail-mcp
Provides Gmail integration for sending and receiving email with attachment staging, support for multiple Google accounts, and server-enforced permission controls on mailbox mutations.
Click on "Deploy 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-mcpSave the attachment from the latest email to my Desktop."
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.
Gmail MCP for Claude
A Gmail Model Context Protocol server that moves attachments to and from your disk, works across several Google accounts, and puts every mailbox mutation behind a permission model the server enforces rather than the model.
Status: pre-release. The Worker, Google OAuth, Gmail tools and macOS companion are implemented. Local tests cover the protocol and recovery paths. Deployment, real Keychain/browser login and installed Claude client checks remain release gates. See the companion runbook.
Why this exists
Two gaps in hosted Gmail connectors show up in daily use.
The first is attachments. A connector returns an attachment's name and id but never its bytes, so you cannot save one to disk. Sending is limited to base64 inlined in the tool call, which stops being usable past a few hundred kilobytes.
The second is permission. Once you connect, a prompt-injected email or a confused model can reach every write the connector exposes. There is no middle setting between full access and none.
This project closes both, without depending on any capability of any hosted connector.
Related MCP server: gmail-mcp-server
What it does
Attachments move in both directions, and the bytes never pass through the model's context. A download becomes an opaque staging handle, and a thin local companion exchanges that handle for a file on disk. Uploads use a private snapshot and a server-approved transfer. Attachment bytes stay out of model context.
Several Google accounts sit under one owner, each with its own alias, policy and send limit. Every write names its account. The model never guesses which mailbox you meant.
Every action resolves to allow, ask or deny, and the server decides. Modifiers such as +external
and +attachment describe the risk in a specific call, and they can only raise the level.
ask means a person approves. The call creates a pending action and returns without touching Gmail. The
payload is held server-side and hashed, so what you approve is what executes. You approve in your browser,
or through MCP URL-mode elicitation where the client supports it. A confirmation code relayed through the
model is never accepted.
Nothing can permanently delete mail. No tool exposes it, and the Google scope this server requests cannot perform one.
Design principles
Claude is not the authority. The MCP client is not the authority. Tool annotations are not the authority. The authenticated server-side policy engine is the authority.
Three consequences run through the code.
Identity is never an argument. The acting user comes from the verified bearer token, and ownership is a database foreign key rather than a habit of remembering to filter.
Approval binds to bytes. A pending action stores its canonical (RFC 8785) payload and the hash of those exact bytes. The attachments an operation reserves are read back out of the approved payload, so nobody can swap in a different file between approval and send.
Ambiguity is a state rather than a guess. When a send may have reached Gmail but the result was never
recorded, the operation becomes delivery_unknown and says so. It is never retried on its own.
Architecture
Claude (claude.ai / Desktop / Claude Code)
│ MCP over Streamable HTTP, bearer scoped "mcp"
▼
┌──────────────────────────────────────────┐
│ Cloudflare Worker (the authority) │
│ Gmail tools · Policy engine │
│ Confirmation engine · Operation journal │
│ Google OAuth · Attachment staging │
│ Audit log · Approval and policy pages │
└──────┬─────────────┬──────────────┬──────┘
│ │ └── KV OAuth clients and grants
│ └── R2 attachment bytes, short lived
└── D1 accounts, policy, approvals, operations, audit
▼
Gmail API
Claude Code / Desktop only
│ stdio
▼
┌──────────────────────────────────────────┐
│ Local companion (thin) │
│ save_attachment · stage_file │
│ bearer scoped "staging" │
└──────────────┬───────────────────────────┘
▼
Your filesystem, confined to configured rootsThe companion knows nothing about Gmail. It moves bytes between staging handles and disk, and enforces the filesystem rules only a process on that filesystem can enforce. Gmail never talks to it.
docs/ARCHITECTURE.md covers this properly. The full design, including the threat model and the reasoning behind each decision, is in the design spec.
Project status
Component | State |
D1 schema, ownership invariants | Built and tested |
Policy engine, actions and modifiers | Built and tested |
Approval engine, atomic claim | Built and tested |
Operation journal, idempotency | Built and tested |
Attachment staging (server side) | Built and tested |
Audit log, scheduled recovery | Built and tested |
MCP endpoint and control tools | OAuth scope and audience checks |
Google OAuth and the approval pages | Implemented; synthetic OAuth tests |
The 38 Gmail tools and the send pipeline | Implemented; synthetic Gmail tests |
Local companion | Implemented; macOS native and stdio tests |
The Worker suite runs inside workerd with a synthetic Google service. The native suite exercises local files and SQLite; Keychain tests use an isolated adapter. This implementation run did not send mail or deploy the Worker.
Getting started
Use Node 22.18 or newer for the companion. Its native helper requires macOS 26.6 or newer, Xcode command-line tools and a local APFS or HFS volume.
git clone https://github.com/Raoof128/gmail-mcp.git
cd gmail-mcp
npm install
npm run verifynpm run verify runs formatting, linting, type checking and the tests. CI runs the same gate, so a green
local run checks the same TypeScript gates. Run npm run verify:native on a supported Mac as a separate gate.
Running the server
Every route is behind real identity. There is no development bearer: a client obtains a token through the OAuth flow, and the browser pages need a Google login as the configured owner.
cp worker/.dev.vars.example worker/.dev.vars
cd worker
npm run migrate:localCreate the Google OAuth client and set the owner following
the Google Cloud runbook. Because the Worker builds its redirect URIs and
audiences as https://<WORKER_HOSTNAME>, the OAuth flows do not complete against a plain-HTTP
wrangler dev; deploy a dev Worker for manual checks. The test suite drives every flow, including the
races, against an in-memory Google inside the real Workers runtime:
npm run verifyPoint a client at the deployed endpoint and it discovers authorization on its own:
npx @modelcontextprotocol/inspector https://<WORKER_HOSTNAME>/mcpLocal companion
Set up the companion after registering its client on the Worker Accounts page. It exposes list_roots, stage_file and save_attachment. V1 refuses overwrites.
Repository layout
shared/ Contracts both halves depend on: action names, error codes, zod schemas
worker/ The Cloudflare Worker: policy, approvals, operations, staging, audit
src/crypto/ canonical JSON, hashing, AES-GCM keyring
src/policy/ recipient trust, argument limits, the policy engine
src/approval/ pending actions and the atomic claim
src/operations/ the external-side-effect journal
src/staging/ attachment ingest, reads and lifecycle
migrations/ D1 schema
companion/ TypeScript stdio client and Swift/Darwin helper
docs/ Architecture, the design spec, and the implementation plansSecurity
SECURITY.md has the threat model, the boundary of what this does not defend against, and how to report a vulnerability. Please do not open a public issue for a security report.
Contributing
CONTRIBUTING.md covers the development loop, how this project tests, and what makes a change easy to review. The Code of Conduct governs participation.
License
MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
Hosted email for AI agents: create inboxes, send, receive, and reply over MCP with scoped API keys
Related MCP Servers
- AlicenseAqualityDmaintenanceA Gmail MCP server that enables Claude to send, search, and read emails using either Gmail API or SMTP/IMAP backend.322 PyPIMIT
- AlicenseNot gradedqualityDmaintenanceA production-ready MCP server that connects Claude AI to Gmail, enabling full email management through natural language.62 npmMIT
- AlicenseNot gradedqualityDmaintenanceA custom MCP server that gives Claude full Gmail control — send directly, read, reply, search, label, and delete emails.62 npmMIT
- AlicenseNot gradedqualityBmaintenanceA local MCP server that gives Claude access to multiple Gmail accounts simultaneously for search, read, draft, send, label, and a scheduled cross-inbox digest, with enforced send policies per mailbox.MIT