mcp-gmail

mcp-gmail

MCP server that connects Claude with Gmail to read, send, delete, and manage messages and labels via the Google Gmail API.

Category
访问服务器

README

mcp-gmail

An MCP (Model Context Protocol) server that connects Claude with Gmail through the Google Gmail API.

Quick Start

  1. Install dependencies: npm install.
  2. Set up Google Cloud credentials — see Google Cloud Console Setup.
  3. Configure environment — copy .env.example to .env.development and add your Google OAuth credentials.
  4. Build: npm run build.
  5. Configure Claude Desktop with dist/mcp-server/index.js and your GMAIL_CLIENT_ID/GMAIL_CLIENT_SECRET (see Configuration).
  6. Start the auth server: npm run dev:auth (separate process; handles OAuth on localhost:3334).
  7. Authenticate — call the authenticate tool in your MCP client, follow the URL, sign in. Tokens land at ~/.mcp-gmail-tokens.json (mode 0600).

Installation

Prerequisites

  • Node.js 22.0.0 or higher
  • npm
  • A Google account for Cloud Console access
npm install

Google Cloud Console Setup

1. Create a project

  1. Open the Google Cloud Console.
  2. Project dropdown → New Project.
  3. Name it (e.g. mcp-gmail) → Create.

2. Enable the Gmail API

  1. APIs & Services → Library.
  2. Search for Gmail APIEnable.

3. Configure the OAuth consent screen

For brand-new projects, Google gates this behind a one-time wizard. If you see "Google Auth Platform not configured yet" with a Get Started button, follow 3a. Otherwise jump to 3b.

3a. First-time setup

  1. APIs & Services → OAuth consent screenGet Started.
  2. App Information: app name, your support email → Next.
  3. Audience: ExternalNext.
  4. Contact Information: your email → Next.
  5. Agree to the user-data policy → ContinueCreate.

3b. Publish the app

  1. OAuth consent screen → Audience.
  2. Publishing statusPublish AppConfirm. (Avoids the 7-day refresh-token expiry of "Testing" mode. The app stays unverified — fine for personal use; you'll see a one-time "advanced → continue" warning during sign-in.)

3c. Configure data access (scopes)

This step is mandatory. If a scope isn't pre-declared here, Google silently drops it from consent, and Gmail API calls return 403 even after a "successful" sign-in.

  1. OAuth consent screen → Data AccessAdd or remove scopes.
  2. Tick https://www.googleapis.com/auth/gmail.modifyUpdateSave.

After changing scopes here, delete the token file (default ~/.mcp-gmail-tokens.json) and re-run the authenticate tool so the consent screen prompts again with the new scope set.

4. Create OAuth credentials

  1. APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID.
  2. Application type: Web application.
  3. Name: anything (e.g. mcp-gmail).
  4. Authorized redirect URIs → add http://localhost:3334/auth/callback (must match GMAIL_REDIRECT_URI).
  5. Create, then copy the Client ID and Client Secret.

Configuration

Environment Variables

Name Required Default Purpose
GMAIL_CLIENT_ID yes OAuth 2.0 Client ID (xxxx.apps.googleusercontent.com).
GMAIL_CLIENT_SECRET yes OAuth 2.0 Client Secret.
GMAIL_REDIRECT_URI no http://localhost:3334/auth/callback Must match the URI registered in Google Cloud.
GMAIL_SCOPES no https://www.googleapis.com/auth/gmail.modify Space-separated OAuth scopes.
GMAIL_AUTH_PORT no 3334 Port the auth server listens on. Must match the redirect URI port.
GMAIL_TOKEN_PATH no ~/.mcp-gmail-tokens.json Token file location. Override to keep multiple accounts side-by-side.
NODE_ENV no dev:*/inspect scripts set development so .env.development loads.

Claude Desktop Configuration

Run npm run build first so dist/mcp-server/index.js exists, then add to your Claude Desktop config:

{
  "mcpServers": {
    "mcp-gmail": {
      "command": "node",
      "args": ["/path/to/mcp-gmail/dist/mcp-server/index.js"],
      "env": {
        "GMAIL_CLIENT_ID": "your-client-id",
        "GMAIL_CLIENT_SECRET": "your-client-secret"
      }
    }
  }
}

A starter is in claude-config-sample.json.

Running From Source (Dev)

cp .env.example .env.development
# edit .env.development with your Google OAuth credentials, then:
npm run dev:mcp        # MCP server
npm run dev:auth       # OAuth server on :3334

Authentication

OAuth runs out-of-band via the standalone auth server:

  1. Start npm run dev:auth (listens on http://localhost:3334).
  2. In your MCP client, call the authenticate tool — it returns a sign-in URL.
  3. Open the URL, sign in with the Google account you want to access, grant the requested scope.
  4. Tokens (including refresh token) are persisted to ~/.mcp-gmail-tokens.json (override with GMAIL_TOKEN_PATH).
  5. The MCP server reads that file and refreshes tokens transparently when they expire.

To force re-authentication (or if the refresh token is revoked), delete the token file and call authenticate again.

Scope troubleshooting. If Gmail API calls return 403 after a successful sign-in, inspect the scope field in the token file — Google only grants scopes that are pre-declared on the OAuth consent screen → Data Access tab (see step 3c). If gmail.modify is missing from scope, add it to Data Access, delete the token file, and re-authenticate.

Tools

31 tools across six areas. Resource-scoped names follow <resource>_<action>; auth tools are server-level and don't fit that shape. Default OAuth scope: https://www.googleapis.com/auth/gmail.modify.

auth

Tool Purpose
about Server version, scopes, token store path.
authenticate Returns the URL to start Google OAuth consent.[^auth-server]
check-auth-status Whether a token is persisted + scope/expiry metadata.[^no-token]

label

Tool Purpose
label_list List all system + user labels with id and name.
label_create Create a user label.
label_update Rename a user label.[^system-labels]
label_delete Delete a user label.[^system-labels] [^label-delete-effect]

message

Tool Purpose
message_search Gmail-query search at message granularity.[^paginated]
message_get Full message: headers, body, label ids, attachment refs.[^html-strip]
message_get_raw Write the raw RFC 2822 message to outputPath (e.g. .eml).[^raw-no-body]
message_label Add label ids to a message.
message_unlabel Remove label ids from a message.
message_mark_read Remove the UNREAD label.[^sugar]
message_mark_unread Add the UNREAD label.[^sugar]
message_archive Remove the INBOX label.[^sugar]
message_trash Move to Trash via messages.trash.[^trash]
message_batch_modify Add/remove labels on up to 1000 messages in one call.[^batch-modify]

attachment

Tool Purpose
attachment_get Download an attachment, to disk via outputPath or inline.[^attach-inline]

thread

Tool Purpose
thread_search Gmail-query search at thread granularity.[^paginated] [^thread-shape]
thread_get Full thread: every message with headers, body, label ids, attachments.
thread_label Add label ids to every message in a thread.
thread_unlabel Remove label ids from every message in a thread.
thread_mark_read Remove the UNREAD label from every message in the thread.[^sugar]
thread_mark_unread Add the UNREAD label to every message in the thread.[^sugar]
thread_archive Remove the INBOX label from every message in the thread.[^sugar]
thread_trash Move every message in the thread to Trash via threads.trash.[^trash]

draft

Tool Purpose
draft_create Create a Gmail draft (saved, never sent).[^draft-shape]
draft_update Replace an existing draft's contents (same fields as draft_create).
draft_list List drafts with headers + snippet; optional query filter.[^paginated]
draft_get Get a draft's full headers, body, label ids, and attachment refs.
draft_delete Permanently delete a draft (does not go to Trash).

This server deliberately exposes draft creation but no sending tool. The user reviews drafts in Gmail and clicks Send — Claude never directly delivers mail. The OAuth scope technically permits sending; the MCP surface does not.

[^auth-server]: The auth server must be running on :3334.

[^no-token]: Never returns access or refresh token values.

[^system-labels]: System labels (INBOX, SENT, etc.) cannot be renamed or deleted; Gmail rejects the request.

[^label-delete-effect]: Gmail removes the label from every message that had it; the messages themselves are untouched.

[^paginated]: Returns {<items>, nextPageToken?}. Pass nextPageToken back as pageToken to fetch the next page; it's omitted on the last page.

[^html-strip]: If the message has no text/plain part, the HTML body is stripped and returned instead.

[^raw-no-body]: Returns {messageId, path, sizeBytes}. The body never travels through the response, so this is safe for messages with large attachments. Subject/date aren't returned — with format=raw Gmail does not break out headers (use message_get).

[^attach-inline]: With outputPath, writes the decoded bytes and returns {messageId, path, sizeBytes}. Without it, returns {filename, mimeType, data} (base64url) — suitable for small attachments only.

[^thread-shape]: Each thread carries id, snippet, messageCount, latest-message headers, and the union of label ids across all messages.

[^draft-shape]: Plain-text body, attachments by file path. With replyToMessageId we wire In-Reply-To, extend References, prepend Re: to Subject, and tie the draft to the right thread. [^sugar]: Sugar over messages.modify / threads.modify so callers don't have to know the magic system-label id. [^trash]: Recoverable for ~30 days from Gmail's Trash UI. Permanent deletion (messages.delete / threads.delete) is intentionally not exposed. [^batch-modify]: Backed by Gmail messages.batchModify. At least one of addLabelIds or removeLabelIds is required. Returns {count, messageIds, addLabelIds, removeLabelIds} echoing the operation; Gmail returns 204 No Content on success.

Security Model

  • Secrets (GMAIL_CLIENT_SECRET) come from env vars only; never committed. .env* files are gitignored except .env*.example templates.
  • OAuth tokens live at GMAIL_TOKEN_PATH (default ~/.mcp-gmail-tokens.json), mode 0600.
  • Token writes are atomic — temp file + rename(). A crash mid-write cannot corrupt the token file.
  • Token values are never logged or returned by any MCP tool. The check-auth-status tool exposes presence flags and metadata only.
  • The auth server binds to localhost:3334 only and accepts a single OAuth callback at a time; CSRF state entries expire after 10 minutes.
  • If the token file is lost, revoked, or you want to switch Google accounts, delete the file and re-authenticate.

Development

npm run dev:mcp        # tsx watch, MCP server
npm run dev:auth       # tsx watch, OAuth server
npm run start:mcp      # build then run from dist/
npm run start:auth     # build then run auth server from dist/
npm run inspect        # MCP Inspector against TS source
npm test               # vitest
npm run typecheck      # tsc --noEmit
npm run lint:check     # Biome
npm run lint:fix       # Biome auto-fix (--unsafe)
npm run lint:md        # prettier + markdownlint for *.md

推荐服务器

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 模型以安全和受控的方式获取实时的网络信息。

官方
精选