gmail-mcp

Your Gmail accounts, served to any MCP client, from your own Cloudflare Worker. Roughly ten minutes to deploy.

27 tools OAuth 2.1 + PKCE multi-account scope gmail.modify MIT
MCP clientClaude Code · claude.ai · mobile
your WorkerOAuth server + agent
Gmail APIone mailbox per grant

Every connection performs its own Google sign-in, so two mailboxes can be connected to one deployment at the same time — each permanently bound to the account chosen at its consent screen. Your refresh tokens stay in your own Cloudflare account.

1 Google Cloud

Create a project and switch the Gmail API on.

PROJECT="gmail-mcp-$(openssl rand -hex 3)"
gcloud auth login
gcloud projects create "$PROJECT" --name="gmail-mcp"
gcloud config set project "$PROJECT"
gcloud services enable gmail.googleapis.com

The consent screen and the OAuth client have no API, so these two happen in the Cloud console:

  1. OAuth consent screenExternal → app name and your email, then under Audience press Publish app. Left in Testing, Google expires every refresh token after 7 days and each connection dies with its token. Published, sign-in shows an unverified-app warning and up to 100 accounts can connect.
  2. Credentials → Create credentials → OAuth client IDWeb application, with one authorized redirect URI:
    https://<your-host>/callback
    Keep the client ID and secret for the next step.
Adding http://localhost:8788/callback as a second redirect URI now saves a trip back if you ever run bun run dev.

2 Cloudflare

Clone and let the setup script do the rest.

git clone https://github.com/mkpoli/gmail-mcp && cd gmail-mcp
bun install
bun run setup

bun run setup asks which domain to answer on, creates or reuses the KV namespace, prompts for each secret, generates the cookie key, and deploys. It is safe to re-run — every step can be skipped.

3 Decide who may sign in

ALLOWED_EMAILS is checked against the address Google reports as verified, after consent and before any grant exists.

ValueWho gets in
emptynobody — fail-closed default
you@gmail.com, work@co.comexactly those accounts
*@your-company.comany account in that domain
*any verified Google account
A grant only ever reaches the mailbox that authenticated it, so widening this list never widens access to accounts already connected. What * hands strangers is the use of your deployment, and your Google client's quota, for their own mail.

4 Connect

No client ID or secret on the client side — MCP clients register themselves.

claude mcp add --transport http gmail-personal https://<your-host>/mcp
claude mcp add --transport http gmail-work     https://<your-host>/mcp/work

Run /mcp in Claude Code to authenticate each one, signing in with the matching Google account. In claude.ai: Settings → Connectors → Add custom connector, paste the URL, leave the credential fields empty.

Any single-segment label works — /mcp/work, /mcp/family. It exists so clients that refuse two servers sharing a URL can still hold several mailboxes.

5 What you get

Read — search with Gmail operators, read messages and threads, download attachments
Compose — send, reply to everyone with quoting, full draft lifecycle, attachments and inline images
Organize — labels including nested ones, batch changes over many messages, reversible trash

Japanese, Chinese, emoji, and right-to-left text survive the round trip: subjects and filenames are RFC 2047 encoded, bodies carry their declared charset.