gmail-multi-mcp

gmail-multi-mcp

MCP server exposing multiple Google Workspace Gmail accounts to Claude, with support for verified send-as aliases and opt-in sending.

Category
Visit Server

README

gmail-multi-mcp

MCP server exposing several Google Workspace accounts — across separate orgs and domains — to Claude at the same time, with verified send-as alias support.

Why this exists

The built-in Gmail connector (https://gmailmcp.googleapis.com/mcp/v1) authenticates one Google identity and its create_draft takes no from parameter, so it can only ever draft as the connected account. Adding a second custom connector for a second account is blocked separately: Claude keys custom connectors by URL alone and rejects a duplicate URL.

So this is one server holding N accounts, with an account argument on every tool and a validated from argument on the compose tools.

Tools

Tool Purpose
list_accounts Configured accounts and their keys
list_send_as Send-as identities on an account, and which are usable
search_messages Gmail query syntax search
get_message One message, full bodies
get_thread Every message in a thread
list_drafts Drafts, optionally filtered
create_draft Create a draft, optionally as an alias or as a threaded reply
update_draft Merge changes into an existing draft
send_draft Send an existing draft — only if GMAIL_MULTI_ALLOW_SEND=1
send_message Compose and send — only if GMAIL_MULTI_ALLOW_SEND=1

Sending is off by default. Routines run unattended with no approval step, so the send tools are not even registered unless you opt in.

Setup

1. One OAuth client per Workspace org

This is the part that determines whether the whole thing works. The Gmail scopes used here are restricted, which means:

  • External + Testing → refresh tokens expire after 7 days. Unusable.
  • External + Published → Google verification plus an annual CASA Tier-2 security assessment. Weeks of work.
  • Internal → no verification, refresh tokens do not expire. ✅

An Internal app is only internal to one org, so three orgs need three OAuth clients. For each one, signed in as an admin of that domain:

  1. Google Cloud Console → create or pick a project owned by that Workspace org.
  2. APIs & Services → Library → enable Gmail API.
  3. APIs & Services → OAuth consent screen → User Type Internal → fill in app name and support email.
  4. Data access / Scopes → add:
    • https://www.googleapis.com/auth/gmail.readonly
    • https://www.googleapis.com/auth/gmail.compose
    • https://www.googleapis.com/auth/gmail.settings.basic
  5. Credentials → Create credentials → OAuth client ID → application type Desktop app. Desktop clients accept loopback redirects on any port, so there is nothing to register. Copy the client ID and secret.
  6. In that org's Admin console → Security → Access and data control → API controls → App access control, confirm the app is not blocked. Restricted scopes are blocked by default in some orgs; if so, allowlist it by client ID and mark it Trusted.

2. Authorize each account

Run once per account. It prompts for the three values and opens your browser:

npm run auth

⚠️ Do not use npm run auth -- --account x --client-id y. npm's PowerShell shim strips flag names and forwards only their values, so the script receives positional junk and exits. For non-interactive use, call node directly — that passes flags intact:

node src/auth-cli.js --account work --client-id <id> --client-secret <secret>

Credentials land in ~/.gmail-multi-mcp/accounts.json at mode 0600. The --account value is the key you will pass as account in every tool call, so keep it short.

This one file is deliberately kept outside Drive: it holds three sets of OAuth client secrets and non-expiring refresh tokens, and those should not sync to cloud storage. Everything else lives here in _Shared Tools.

3. Point Claude at it

Claude runs the bundle, not src/index.js — see Why a bundle.

{
  "mcpServers": {
    "gmail-multi": {
      "command": "node",
      "args": ["H:\\My Drive\\_Shared Tools\\gmail-multi-mcp\\gmail-multi-mcp.mjs"]
    }
  }
}

To enable sending, add "env": { "GMAIL_MULTI_ALLOW_SEND": "1" }.

Why a bundle

This project lives in Google Drive, and Drive cannot host node_modules. Syncing ~3,500 dependency files truncated @modelcontextprotocol/sdk/package.json to 0 bytes, which surfaced as a misleading Invalid package config at startup. Drive also refuses directory junctions (Incorrect function), so node_modules cannot be redirected off the volume either.

So dependencies are installed on local disk, bundled into a single file, and only that file is written back to Drive. It needs nothing but Node to run, and there is no dependency tree left for sync to corrupt.

After changing anything under src/:

npm run build

then restart Claude Desktop. src/auth-cli.js is not bundled — it imports only Node built-ins, so it runs from Drive as-is.

Cloud routines

Cloud sessions have no access to your home directory, so credentials come from the environment instead. Set GMAIL_MULTI_ACCOUNTS on the cloud environment to the contents of accounts.json — raw JSON, or base64 if the shell mangles quotes — and commit a .mcp.json to a repository the routine clones.

*.googleapis.com and accounts.google.com are already on the default Trusted network allowlist, so no allowlist change is needed.

The two things this server is careful about

Unverified From addresses. Gmail does not reliably error when you set a From the account cannot send as — it silently substitutes the primary address. A draft meant to go out as one business quietly goes out as another. So every from is checked against users.settings.sendAs.list first and rejected if it is not verified. The primary address reports an empty verificationStatus rather than accepted, so it is admitted via isPrimary.

Draft updates. drafts.update is a full PUT replace, not a patch. update_draft reads the existing draft, merges your changes over it, and rebuilds — preserving threadId and the In-Reply-To/References headers, without which the draft silently detaches from its thread. The draft id is stable across updates even though the underlying message id changes each time, so key any state off draftId.

Development

npm test

Covers the MIME builder: base64url alphabet, multipart structure, RFC 2047 header encoding, threading headers, line wrapping, and payload extraction. No parser is needed — drafts are read back with format=full, which returns a decoded tree.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured