Skip to main content
Glama
reconexus

multi-gmail-cowork-mcp

by reconexus

multi-gmail-cowork-mcp

Open in Google Cloud Shell

A small, self-hosted MCP server that lets one Claude custom connector search, read, compose, and send through multiple, independently-authenticated Gmail accounts. Built to be deployed by anyone into their own Google Cloud project, with zero shared infrastructure and zero code changes required per deployment.

Claude Cowork
      |
      v
Your private Multi-Gmail MCP  (your own Cloud Run project)
      |
      +-- Gmail account: "personal"
      +-- Gmail account: "work"
      +-- Gmail account: "billing"
      +-- ...more, added any time via the admin page

Ask Claude things like:

  • "Search my work Gmail for emails from David."

  • "Search all connected Gmail accounts for 'invoice 4831'."

  • "Read the latest email from ACH Works, whichever account received it."

  • "Which of my Gmail accounts received an email from John yesterday?"

Every result is explicitly attributed to the account alias and email address it came from. If you ask for an account that isn't connected, or whose authorization has expired, you get a clear error — this server never silently substitutes a different account.

What this is not

Gmail only. No Calendar, Drive, Docs, Sheets, or Contacts. No permanent-delete tool. No shared backend, no central account, no telemetry.

Related MCP server: Gmail MCP

Privacy model — who can see your email

Google  <->  Your Google Cloud deployment  <->  Claude / Anthropic
  • You deploy this into your own Google Cloud project, using your own Google OAuth client and your own Cloud Run service.

  • Google issues/can revoke the OAuth grants; it sees ordinary OAuth traffic.

  • Your deployment is the only place Gmail refresh tokens are ever stored.

  • Claude/Anthropic sees whatever the tools return when Claude calls them (same as any other MCP tool) — nothing more, nothing when you're not using it.

  • The author of this repository sees none of your email, ever. There is no shared server. Your cousin's deployment and your deployment have nothing in common except the source code.

Read SECURITY.md for the full trust-boundary and design-rationale writeup — including exactly why authentication is implemented the way it is, and this project's known limitations. This README does not repeat that reasoning.

Architecture at a glance

  • Language/runtime: TypeScript on Node.js 20+, using the official @modelcontextprotocol/sdk and Google's google-auth-library.

  • Transport: Streamable HTTP (the current MCP-recommended remote transport), stateless — every request is handled independently, so it scales cleanly on Cloud Run with no session affinity required.

  • Claude <-> server auth: MCP OAuth 2.1 authorization-code flow with PKCE/S256, Dynamic Client Registration, short-lived access tokens, rotating refresh tokens, and deployment-local authorization state in Secret Manager.

  • Server <-> Google auth: standard OAuth 2.0 with PKCE, one grant per connected Gmail account, gmail.modify scope (read, compose, send, and mailbox modification; no permanent delete).

  • Account storage: one Google Secret Manager secret holding a small JSON array (alias, email, refresh token). No database.

  • Admin UI: a few unstyled HTML pages behind HTTP Basic Auth — just enough to connect or disconnect accounts.

Prerequisites

  • A Google account and a Google Cloud project with billing enabled (the bootstrap prints the exact billing page if billing is not linked).

  • A Claude plan that supports custom connectors (for connecting to Cowork/claude.ai).

  • Nothing else is required for a deployment: Google Cloud Shell already includes gcloud, curl, openssl, and jq.

Cost and billing

Cloud Run requires a billing-enabled project. This deployment is sized for personal/small-business use: min instances 0 (scales to zero when idle) and max instances 3. Normal usage — a handful of searches, reads, and sends per day — stays well inside Google Cloud's Always Free allowance for Cloud Run, so the realistic ongoing cost is $0. That is not a guarantee: a sustained burst of requests beyond the free allowance would incur normal Cloud Run charges. The bootstrap prints an optional budget-alert link if you want a notification before any spend.

  1. Open this repository in Google Cloud Shell using the button above (or use Open in Cloud Shell on GitHub).

  2. Authenticate if Cloud Shell asks, then run:

./scripts/bootstrap.sh

The script asks you to select a project (or creates one), checks billing, enables the required APIs, creates the dedicated Cloud Run runtime service account, assigns only the Secret Manager roles it needs, creates all secrets, deploys Cloud Run, and prints PASS/FAIL checks. It is safe to rerun: existing secrets, account records, OAuth credentials, and Cloud Run services are preserved.

The script never prints a password, OAuth client secret, refresh token, account-store JSON, or MCP OAuth token. Secret values are written as exact bytes (no trailing-newline credential bug). Use ./scripts/bootstrap.sh --check for a read-only Cloud Shell prerequisite check.

The one unavoidable Google browser step

Google does not provide a safe, supported API/CLI operation for creating a general-purpose web OAuth client. When the bootstrap asks, open the Google Auth Platform page it prints and do the following:

  • Configure the app as External, add the scope https://www.googleapis.com/auth/gmail.modify, and add the Gmail addresses you will use as test users.

  • Create an OAuth client with application type Web application.

  • Enter the exact callback URI printed by the script: https://<your-cloud-run-host>/oauth/google/callback.

  • Paste the resulting Client ID and Client Secret into the hidden prompts in Cloud Shell.

If Google shows an unverified-app warning, that is expected for a personal deployment. Publish the consent screen to In production if you want refresh tokens to remain valid beyond the Testing-mode seven-day limit; verification is not required for a personal/small deployment.

At the end, bootstrap prints the Admin URL, exact Google OAuth callback URL, MCP URL, and the next human action. Claude authenticates to the MCP endpoint through its supported OAuth flow; there is no static connector header to copy or put in a URL.

Connect Gmail accounts

  1. Retrieve the admin password (generated by the bootstrap, never printed) with the command the bootstrap printed at the end:

    gcloud secrets versions access latest --secret=admin-password --project=YOUR_PROJECT_ID

    Then open the printed Admin URL and sign in with username admin and that password.

  2. Enter a short alias such as personal or work, click Add Gmail Account, and complete Google authorization. The authorization URL requests consent select_account, so Google shows the account chooser every time. The address displayed after callback is the address Google actually authorized; it is not taken from the alias field.

  3. Repeat for as many Gmail accounts as desired. Each alias is independent and all results are attributed to both alias and verified Gmail address.

Connect Claude Cowork

In Claude, open Settings → Connectors → Add custom connector and enter exactly:

  1. Connector name: Multi Gmail

  2. Remote MCP URL: the printed URL ending in /claude-mcp

  3. OAuth Client ID: leave blank (the server supports Dynamic Client Registration)

  4. OAuth Client Secret: leave blank

The /mcp route remains available for existing clients; use /claude-mcp for new Claude connectors so its OAuth resource identity is independent of older connector records.

Click Add, then Connect. Claude discovers the MCP authorization metadata, registers itself, and opens the deployment's Authorize MCP access page. Sign in there with username admin and the admin password stored in your own admin-password Secret Manager secret, then approve. Claude redirects through its callback at https://claude.ai/api/mcp/auth_callback, stores the OAuth tokens, and reconnects. Do not enter the Gmail OAuth client ID or secret in Claude — those belong only to Google's Gmail setup.

After the connector is connected, ask Claude to call list_accounts, then run an alias-specific search for each account and search_all_accounts to verify attribution.

Verify your deployment

scripts/acceptance_test.mjs proves every tool works end-to-end against your own deployment — account isolation, no-fallback on a bad alias, drafts, and send with arrival and correct From identity. It performs the full MCP OAuth flow as a real remote client and never prints tokens:

MCP_BASE_URL=https://your-service.run.app \
  MCP_ADMIN_PASSWORD='...'   # Secret Manager -> admin-password
  node scripts/acceptance_test.mjs

The send test sends one email account-A → account-B and one account-B → account-A, so the recipient is always an account you own. Set SKIP_SEND=1 to skip sends.

Local development (optional)

For source development only, install Node.js 20+, run npm install, copy .env.example to .env, set TOKEN_STORE=file, and use npm run dev. Local Gmail OAuth requires a separate OAuth client callback such as http://localhost:8080/oauth/google/callback; do not reuse or commit production secrets. Windows users can use scripts/setup.ps1 and scripts/deploy.ps1 instead of the Cloud Shell bootstrap.

Reauthorizing / revoking accounts

After upgrading from the earlier read-only release, each existing account is marked Needs Gmail permission upgrade. Open /admin, click Reauthorize for the same alias, and complete Google's consent screen. The callback verifies that Google actually granted https://www.googleapis.com/auth/gmail.modify before replacing that alias's stored refresh token. Until then, read tools continue to work with the old grant, while write tools return a clear reauthorization message; no other alias is ever used.

To remove access, click Disconnect next to an account. This revokes the grant with Google (best-effort) and removes it from the credential store immediately — Claude will get a clear "not connected" error if it's asked for that alias afterward, never a silent fallback.

To reconnect the same alias after revoking access on Google's side, use Connect account with the same alias — it overwrites the old record only after successful Google authorization.

Write tools and safety

The deployed server exposes create_draft and send_email. Both require an explicit connected-account alias and never fall back to another account. send_email always sends from the selected Gmail identity; the result includes that verified address. The tools use gmail.modify, not the broader mail.google.com scope, and there is no permanent-delete tool. Claude connector permissions should allow read tools automatically while keeping create_draft and send_email set to Needs approval.

Updating and rotating

  • Update the deployment after changing source or to pick up a new secret version: rerun ./scripts/bootstrap.sh (idempotent — preserves accounts, tokens, and the OAuth client) or, on Windows, scripts/deploy.ps1. Existing Gmail connections and the Claude connector are unaffected.

  • Rotate the admin password: add a new Secret Manager version for admin-password and redeploy. Existing Claude connector tokens stay valid (they are not derived from the admin password); only future MCP consent approvals use the new password.

  • Rotate oauth-state-secret: this signs every MCP OAuth token, so rotating it invalidates the Claude connector's existing tokens — reconnect Claude afterward. Pending Gmail-linking state tokens (10-minute lifetime) also invalidate; connected Gmail accounts are untouched.

  • Rotate a Gmail account's grant: reconnect the alias from the admin page (see Reauthorizing / revoking accounts).

How to delete everything

  • Remove Gmail access: disconnect each account from /admin, or revoke access directly at https://myaccount.google.com/permissions.

  • Tear down the deployment:

    gcloud run services delete multi-gmail-mcp --region us-central1
    gcloud secrets delete mcp-oauth-state admin-password oauth-state-secret google-client-id google-client-secret gmail-mcp-accounts
    gcloud iam service-accounts delete multi-gmail-mcp-run@YOUR_PROJECT_ID.iam.gserviceaccount.com
  • Delete the OAuth client: Cloud Console -> APIs & Services -> Credentials -> delete the OAuth client ID, and optionally delete the OAuth consent screen configuration.

  • Or simplest: delete the whole Google Cloud project.

Troubleshooting

  • "Account needs to be reconnected" errors: the stored refresh token was rejected by Google (revoked, expired, or the consent screen is stuck in "Testing" — see below). Reconnect it from /admin.

  • Refresh tokens keep dying after ~7 days: your OAuth consent screen is still in "Testing" publishing status. Publish it to "In production" (see step 3) — it can stay unverified, that's fine for personal use.

  • Claude can't reach the connector / connection fails silently: confirm the service URL resolves over plain HTTPS with no redirect to a different host, then open the MCP URL ending in /claude-mcp in Claude and click Connect again. The server must return OAuth metadata and a 401 challenge when called without an access token; no static request header is required.

  • gcloud run deploy fails on APIs not enabled: re-run scripts/setup.ps1, or run gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.com gmail.googleapis.com iam.googleapis.com.

  • Local dev can't reach Google over HTTPS (certificate errors): this is almost always a local machine issue (a corporate proxy or antivirus doing TLS interception), not a bug in this project — check your machine's trusted root certificates.

Google OAuth Testing vs. longer-term use

Google Cloud OAuth clients start in Testing publishing status. While in Testing, refresh tokens for sensitive/restricted scopes (which includes gmail.modify) expire after 7 days, regardless of how few users you have — this will silently break the connector on a weekly basis if left as-is.

The fix is not Google verification (a multi-month process built for public SaaS). It's simpler: click Publish app to move the consent screen to In production. For an app requesting only gmail.modify and staying under 100 total connected Google accounts, Google's own documentation treats this as a fully supported personal/small-scale use case — no verification required. The only visible effect is that each newly-connected account sees a one-time "Google hasn't verified this app" click-through warning before granting consent. That warning is expected; it does not mean anything is misconfigured. See SECURITY.md for the underlying rules and sources.

Repository layout

src/            TypeScript source (server, MCP tools, admin/setup UI, OAuth flows)
scripts/        bootstrap.sh (Cloud Shell), setup.ps1/deploy.ps1 (Windows),
                acceptance_test.mjs (verify any deployment end-to-end)
.env.example    Local-dev configuration template (placeholders only)
SECURITY.md     Trust model, design rationale, known limitations

License

MIT — see LICENSE.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Server for Gmail integration in Claude Desktop with auto authentication support. This server enables AI assistants to manage Gmail through natural language interactions.
    26,678
    1,165
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A server that allows Claude to search and retrieve emails from your Gmail account, supporting functions like searching emails, retrieving full content of specific emails, and listing recent messages.
    7
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server that enables Claude AI to interact with Gmail, supporting email sending, reading, searching, labeling, draft management, and batch operations through natural language commands.
    2
    MIT
  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A Model Context Protocol server that enables Claude to interact with Gmail through a secure OAuth2 connection, providing email management capabilities like listing, sending, deleting, and organizing emails.

View all related MCP servers

Related MCP Connectors

  • Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…

  • Manage Gmail messages, threads, labels, drafts, and settings from your workflows. Send and organiz…

  • Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.

View all MCP Connectors

Latest Blog Posts

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/reconexus/multi-gmail-cowork-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server