multi-mail-mcp

multi-mail-mcp

Enables AI agents to access multiple Gmail/Google Workspace accounts for searching and reading mail, calendars, and attachments.

Category
访问服务器

README

multi-mail-mcp

An MCP server that gives an AI agent access to several Gmail / Google Workspace accounts at once — searching and reading mail, reading and updating calendars, and downloading and uploading attachments.

Runs as a single Node process with a SQLite database and a small web UI.


How it fits together

┌──────────────────────────────────────────────────────┐
│ multi-mail-mcp        (one process, port 8456)       │
│                                                      │
│   /mcp                    MCP endpoint (bearer key)  │
│   /                       web UI — mailboxes, keys   │
│   /oauth/google/callback  Google sign-in + consent   │
│   /reauth/<token>         one-click access renewal   │
│   /files/attachment/…     signed attachment download │
│   /files/upload/…         signed attachment upload   │
│                                                      │
│   SQLite: users, mailboxes, keys, staged uploads     │
└──────────────────────────────────────────────────────┘
                      │
                      └──► Gmail API + Calendar API, per mailbox

Mail is not mirrored locally. Every search goes straight to Gmail, so results are always current and there is no index to maintain. Searching several mailboxes runs the query against each in parallel and merges the results newest-first.


Getting started

npm install
npm run build
npm start

Then open your PUBLIC_BASE_URL in a browser and sign in with Google.

  1. Sign in. The account you sign in with is connected as your first mailbox automatically — one flow does both.

  2. Connect the other mailboxes from the dashboard.

  3. Create an API key. The dashboard then shows the key once, alongside a ready-to-run registration command with the key already filled in, and a copy button for each:

    claude mcp add --transport http multi-mail \
      https://your-host.example.com/mcp \
      --header "Authorization: Bearer <your-key>"
    

    Keys are 37 characters (mmcp_ plus 192 bits of randomness) and are stored only as a SHA-256 hash, so a key that isn't copied at creation time is gone.

Sign-in rules

There are no passwords. Google is the only way in, and which user you become follows three rules, checked in order:

  1. The address is a known user → sign in as them.
  2. The address is already connected as a mailbox on some user → sign in as that user. This is what makes all of your addresses work as ways into one account instead of creating a separate user per address.
  3. The address is on the allowlist (ALLOWED_LOGIN_EMAILS, then managed in the admin UI) → create a new user. The first user created becomes administrator.

Anything else is refused. The service is on a public URL, so this matters.


Renewing Google access

Google expires refresh tokens after 7 days while the OAuth app is in Testing mode, so this will happen often at first. The whole flow is built around making it a single click:

  • Any tool call that hits a dead grant returns an ACTION REQUIRED message containing a ready-made link. The agent can hand that link straight to you.
  • Multi-account operations (search_messages, list_events, find_free_time) don't fail outright when one mailbox is stale — they return results from the working mailboxes and list the broken ones with their renewal links.
  • list_accounts always shows current status, and get_reauth_url produces a link on demand.
  • Opening the link takes you straight to Google consent for that specific address. No prior sign-in needed; the link itself is the authorisation.

Links are HMAC-signed and valid for 24 hours. The callback refuses to proceed if you sign in as a different Google account than the one the link was issued for.

To stop the weekly expiry, publish the OAuth app: Google Cloud Console → APIs & ServicesOAuth consent screenPublish app. You will get an "unverified app" warning screen once per consent (click AdvancedGo to…), but refresh tokens then stop expiring. Full verification is only needed to go past 100 users.


Tools

Accountslist_accounts, check_account, get_reauth_url

Mailsearch_messages, get_message, get_thread, list_labels, modify_labels, send_message, create_draft, get_attachment_url

Calendarlist_calendars, list_events, get_event, create_event, update_event, delete_event, respond_to_event, find_free_time

Attachmentscreate_upload_url, list_uploads

Most tools take an optional account argument naming the mailbox. Omit it when only one mailbox is connected; with several, the tool asks you to name one rather than guessing — sending from the wrong address is not worth being clever about.

search_messages uses Gmail query syntax and returns compact summaries without bodies, so a broad search doesn't flood the context window. Follow up with get_message or get_thread for the text and the attachment list.

Search results deliberately carry no attachment flag: Gmail's metadata format returns headers but not the MIME part tree, so any such field could only ever be wrong. Filter with the has:attachment operator in the query instead — it runs server-side and costs nothing.

Attachments

Downloading — messages come back with a signed downloadUrl per attachment. The URL streams from Gmail on demand; nothing is stored on the server. Valid for one hour.

Uploadingcreate_upload_url reserves a slot and returns a URL to PUT to:

curl -X PUT --upload-file ./report.pdf "<uploadUrl>"

Then pass the returned uploadId in the uploadIds array of send_message or create_draft. Staged files are deleted when the slot expires.


Admin CLI

npm run cli -- allow <email>            # add to the sign-in allowlist
npm run cli -- users                    # list users
npm run cli -- accounts <user-email>    # mailboxes and their health
npm run cli -- key <user-email> [name]  # issue an API key
npm run cli -- keys <user-email>        # list keys
npm run cli -- audit [n]                # recent audit log

Configuration

All settings live in .env (see .env.example). The ones that matter:

Variable Purpose
PORT Listen port, e.g. 8456 behind a reverse proxy or tunnel.
PUBLIC_BASE_URL Public origin. Used to build the OAuth redirect and every signed URL.
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET OAuth client, type Web application.
ALLOWED_LOGIN_EMAILS Comma-separated addresses allowed to create a user.
ENCRYPTION_KEY 32 random bytes, base64. Encrypts refresh tokens at rest.
URL_SIGNING_SECRET 32 random bytes, base64. Signs download, upload and renewal links.
MAX_UPLOAD_BYTES Attachment size cap, default 25 MB (Gmail's own ceiling).

The redirect URI registered in Google Cloud Console must match <PUBLIC_BASE_URL>/oauth/google/callback exactly.

Rotating ENCRYPTION_KEY or URL_SIGNING_SECRET invalidates existing data: a new encryption key makes every stored refresh token unreadable, so every mailbox has to be reconnected.


Security notes

  • Google refresh tokens are encrypted at rest with AES-256-GCM. Access tokens are cached encrypted too and refreshed a minute before expiry.
  • API keys are stored as SHA-256 hashes. The plaintext is shown once, at creation, and is not recoverable.
  • Every tool is bound to the authenticated user. A fresh MCP server is built per request with that user closed over, so no argument can reach another user's mailboxes.
  • Signed URLs are typed and time-limited. A download token cannot be replayed as an upload token, and a tampered token fails HMAC verification.
  • Uploaded filenames never touch the filesystem path. Files are stored under a random name; the display name lives only in the database.
  • gmail.modify is requested, not gmail.full — an agent can archive, label and trash, but cannot permanently delete mail.
  • Anyone holding an API key can read, send and delete mail in every connected mailbox. Treat keys as you would the mailbox passwords themselves, and revoke them from the dashboard when a client is retired.

Running it as a service

# /etc/systemd/system/multi-mail-mcp.service
[Unit]
Description=multi-mail-mcp
After=network-online.target

[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/multi-mail-mcp
ExecStart=/usr/bin/node dist/index.js
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now multi-mail-mcp

Development

npm run dev        # watch mode
npm test           # unit tests
npm run typecheck  # types only

Tests cover the parts that are worth testing without live credentials: MIME assembly, Gmail payload parsing, calendar mapping, token signing and expiry, encryption round-trips, and filename sanitisation.

推荐服务器

Baidu Map

Baidu Map

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

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

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

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

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

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

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

官方
精选
本地
TypeScript
VeyraX

VeyraX

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

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

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

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

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

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

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

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选