Gmail多账户管理工具

一个私有MCP服务器和CLI工具,用于链接多个Gmail收件箱并通过标准输入输出提供工具,支持SQLite存储和密码加密。

  • by ideadesignmedia
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 ideadesignmedia/gmail-mcp

使用说明

@ideadesignmedia/gmail-mcp

Private MCP server and CLI that links multiple Gmail inboxes and exposes tools over stdio. Tokens are stored in SQLite and can be encrypted-at-rest with a password. When locked, every command and the MCP server require a password to run.

  • Transport: stdio (suitable for MCP clients that launch a local command)
  • Default DB: ~/.idm/gmail-mcp/db.sqlite
  • Node requirement: >= 18.17

Run with npx (recommended)

You do not need to install anything globally. Use npx to run the CLI and server. On first run, npx will download the package; later runs use the cached copy.

Show help:

npx @ideadesignmedia/gmail-mcp --help

Add an account (loopback OAuth):

# Define or export your Google OAuth client credentials
export GOOGLE_CLIENT_ID=your_client_id
export GOOGLE_CLIENT_SECRET=your_client_secret

# Start the OAuth flow and link the Gmail account
npx -y @ideadesignmedia/gmail-mcp add \
  --client-id "$GOOGLE_CLIENT_ID" \
  --client-secret "$GOOGLE_CLIENT_SECRET"

# The CLI prints a URL; open it in your browser to consent.
# After consenting, the local callback will display "Authentication complete".

Add an account (device code flow; headless-safe):

export GOOGLE_CLIENT_ID=your_client_id
export GOOGLE_CLIENT_SECRET=your_client_secret

npx -y @ideadesignmedia/gmail-mcp add \
  --device \
  --client-id "$GOOGLE_CLIENT_ID" \
  --client-secret "$GOOGLE_CLIENT_SECRET"

Lock the database with a password:

npx -y @ideadesignmedia/gmail-mcp passwd --pass 'your-strong-pass'

Start the MCP server over stdio (for your MCP client to launch):

export GMAIL_MCP_DB_PASS='your-strong-pass'   # only required if the DB is locked
npx -y @ideadesignmedia/gmail-mcp start

Notes for npx usage:

  • -y auto-confirms the download prompt on first run.
  • You can pass --db /custom/path.sqlite to store the database elsewhere.
  • Use --read-only with start to disable write actions (send/label modify).

Quick start (end‑to‑end)

  1. Create a Google OAuth client (see "Google OAuth setup").

  2. Link one or more Gmail accounts:

export GOOGLE_CLIENT_ID=...
export GOOGLE_CLIENT_SECRET=...
npx -y @ideadesignmedia/gmail-mcp add --client-id "$GOOGLE_CLIENT_ID" --client-secret "$GOOGLE_CLIENT_SECRET"
  1. (Optional but recommended) Lock the DB with a password so tokens are encrypted at rest:
npx -y @ideadesignmedia/gmail-mcp passwd --pass 'your-strong-pass'
  1. Point your MCP client to run the server command. Most clients let you configure a command, arguments, and environment variables. An example configuration looks like:
{
  "command": "npx",
  "args": ["-y", "@ideadesignmedia/gmail-mcp", "start", "--read-only"],
  "env": { "GMAIL_MCP_DB_PASS": "your-strong-pass" }
}

Exact configuration format depends on your MCP client. The server speaks stdio.

  1. Use the tools provided by the server from your MCP client (see "MCP tools").

CLI reference

Global options (apply to all commands unless stated otherwise):

  • --db <path>: SQLite DB path (default ~/.idm/gmail-mcp/db.sqlite)
  • --pass <pass>: Database password or new password (also available via GMAIL_MCP_DB_PASS)
  • --read-only: Start server with write operations disabled (only used by start)

Commands:

# Start the MCP server over stdio
npx -y @ideadesignmedia/gmail-mcp start [--db <path>] [--pass <pass>] [--read-only]

# Link a Gmail account (loopback or device flow)
npx -y @ideadesignmedia/gmail-mcp add \
  [--db <path>] [--pass <pass>] \
  [--client-id <id>] [--client-secret <secret>] [--device] [--listen-port <port>]

# List linked accounts
npx -y @ideadesignmedia/gmail-mcp list [--db <path>] [--pass <pass>]

# Remove an account (by email or id)
npx -y @ideadesignmedia/gmail-mcp remove <email|id> [--db <path>] [--pass <pass>]

# Lock the DB, set password, or rotate existing password
npx -y @ideadesignmedia/gmail-mcp passwd [--db <path>] [--pass <new>] [--rotate] [--old-pass <old>] [--hint <text>]

Behavioral details:

  • When the DB is locked, all commands require a password (--pass or GMAIL_MCP_DB_PASS).
  • When unlocked, you can operate without a password and lock later with passwd.
  • passwd --rotate --old-pass <old> --pass <new> rotates the encryption KEK without re‑adding accounts.
  • start --read-only disables gmail-send_message and gmail-label_message tools and prevents modification APIs.

Google OAuth setup

Create a Web application OAuth client in Google Cloud Console and enable the Gmail API.

Loopback (default) flow requirements:

  • Authorized redirect URI: http://127.0.0.1:43112/oauth2/callback
  • The CLI prints the authorization URL; open it manually in your browser.
  • Scopes requested by this tool:
    • https://www.googleapis.com/auth/gmail.readonly
    • https://www.googleapis.com/auth/gmail.modify
    • https://www.googleapis.com/auth/gmail.send
    • openid, email, profile (used to fetch the account email/id on first link)

Device code flow (headless) requirements:

  • No redirect URI needed. You will be shown a verification URL and user code to enter in a browser.

Tips:

  • If you get no refresh_token, ensure access_type=offline and prompt=consent are set and you have not previously granted this client for the user. You can revoke previous grants at https://myaccount.google.com/permissions.

Environment variables

  • GMAIL_MCP_DB_PASS: Password for a locked DB (also accepted via --pass).
  • GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: Used by add if flags are not provided.

MCP tools

The server exposes these tools. Tool names are prefixed with gmail.. Names and parameters are stable and validated with zod. Unless noted, responses mirror the Gmail REST API types.

  1. gmail-list_accounts
  • Input: {}
  • Output: { accounts: Array<{ id: string, email: string, displayName: string | null }> }
  1. gmail-search_mail
  • Input: { query: string, account?: string, limit?: number }
  • Behavior:
    • If the query contains only date operators (after:, before:, older_than:, newer_than:) or is empty: results are sorted by timestamp descending (most recent first). Across multiple accounts, they are merged and sorted together.
    • Otherwise (query includes free text or non-date operators): ordering matches Gmail’s native results per account; multi‑account queries preserve per‑account order without a global sort.
  • Output: Enriched results to reduce follow‑ups:
    • { messages: Array<{ accountId: string, accountEmail: string, messageId: string, threadId: string, subject: string | null, snippet: string, from: string | null, to: string | null, cc: string | null, bcc: string | null, timestamp: number, date: string, labels: Array<{ id: string, name: string }> }> }
    • Notes: timestamp is ms since epoch; date is ISO8601 string. Use gmail-get_message for full decoded body and attachments.
    • Query operators: Supports standard Gmail search syntax, including common operators like from:, to:, subject:, label:, in:, is: (e.g. is:unread, is:starred), has: (e.g. has:attachment), date filters before:, after:, relative older_than:/newer_than:, cc:, bcc:, filename:, size filters larger:/smaller:, boolean OR, and negation with -.
  1. gmail-get_message
  • Input: { account: string, messageId: string }
  • Output: A simplified, human-readable object:
    • { id: string, thread: string, labels: Array<{ id: string, name: string }>, timestamp: number, subject: string | null, from: string | null, to: string | null, cc: string | null, bcc: string | null, body: string, bodyType: 'text' | 'html', attachments: Array<{ filename: string, mimeType: string, size: number, attachmentId: string }> }
    • Notes: body is decoded (not base64url). Prefers text/plain when available, otherwise returns text/html. timestamp is ms since epoch.
  1. gmail-get_thread
  • Input: { account: string, threadId: string }
  • Output: A simplified thread with deduped messages ordered by time:
    • { id: string, messages: Array<SimpleMessage> }, where SimpleMessage matches gmail-get_message output.
    • Each message includes resolved label names and a timestamp field.
  1. gmail-download_attachment
  • Input: { account: string, messageId: string, attachmentId: string }
  • Output: Gmail MessagePartBody with base64url data.
  • Tip: Use gmail-get_message first to list attachments and obtain an attachmentId.
  1. gmail-label_message
  • Input: { account: string, messageId: string, add?: string[], remove?: string[] }
  • Writes: Adds/removes label IDs on a message. Disabled in --read-only mode.
  • Output: Gmail Message resource (post-modify).
  1. gmail-send_message
  • Input: { account: string, to: string, subject: string, text?: string, html?: string, replyToMessageId?: string }
  • Behavior: Builds a minimal RFC822 message (text or html) and sends via users.messages.send. Attachments and custom headers are not yet supported. replyToMessageId is currently accepted but not used to set threading headers.
  • Writes: Sends email on the selected account. Disabled in --read-only mode.
  • Output: Gmail Message resource for the sent message.

Account selection:

  • For any tool, account accepts either the account’s email or its internal id (see gmail-list_accounts).

Security model

  • Stored tokens are encrypted-at-rest when the DB is locked with passwd.
  • Losing the password means losing access to encrypted refresh tokens; there is no recovery.
  • Anyone who can launch the server or CLI with the password can access all linked inboxes.
  • No message bodies or tokens are logged.

Troubleshooting

  • Node not recent enough: ensure Node >= 18.17 (node -v).
  • No refresh token after OAuth: revoke prior grants and try again, ensuring prompt=consent and first-time approval for this client.
  • Locked DB errors: provide --pass or set GMAIL_MCP_DB_PASS for all commands, including list and remove.
  • Device flow polling errors: if you see authorization_pending or slow_down, just wait; the CLI automatically retries.

Optional: global install

You can install globally if you prefer shorter commands:

npm i -g @ideadesignmedia/gmail-mcp
gmail-mcp --help

All examples above work the same without npx once installed globally.