multi-gmail-cowork-mcp

multi-gmail-cowork-mcp

This server enables users to search, read, compose, and send emails across multiple independently-authenticated Gmail accounts through a single Claude custom connector.

Category
访问服务器

README

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.

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.

One-command Cloud Shell setup (recommended)

  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.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
mcp-server-qdrant

mcp-server-qdrant

这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。

官方
精选
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选