Gmail MCP服务器
Gmail的流式HTTP MCP服务器——搜索线程、阅读消息、管理草稿和组织收件箱。
作者 过度
\[!警告\] 您自行负责将此服务器连接到MCP客户端。语言模型可能会出错、误解指令或执行意外操作。查看工具输出,在Gmail中验证结果,并更喜欢小的增量写入。 HTTP/OAuth层是为开发过程中的便利性而设计的,而不是生产级的安全性。如果远程部署,请加强它:适当的令牌验证、安全存储、TLS终止、严格的CORS/源代码检查、速率限制、审计日志记录以及遵守Google OAuth策略。
通知
此repo以两种方式工作:
- 作为一个 节点/HONO服务器 用于本地工作流
- 作为一个 Cloudflare工作人员 用于远程交互
有关Cloudflare的生产部署,请参阅 远程模型上下文协议服务器(MCP).
动机
Gmail的API功能强大,但不是开箱即用的LLM友好型。此服务器侧重于:
- 让LLM了解收件箱状态 单一动作 (
inbox_overview)而不是多个查询 - 提供 丰富的搜索结果 包含主题、发件人、日期,而不仅仅是线程ID
- 支持 批量操作 (
modify_thread一次最多可处理100个线程) - 将API响应映射到 人类可读的反馈 对LLM和用户都有用
- 更安全的写入流程: 先起草,明确发送
简言之,它并不是Gmail API的直接镜像——它是定制的,这样人工智能代理就知道如何有效地使用它。
特性
- ✅ 概述 --获取收件箱统计数据+亮点(未读、已星级、最新帖子)
- ✅ 搜索 --使用Gmail查询语法查找线程,丰富结果
- ✅ 阅读 --获取包含正文内容的完整帖子和消息
- ✅ 标签 --发现用于过滤和组织的标签ID
- ✅ 修改 --批量存档、星形标记、标记已读/未读(最多100个线程)
- ✅ 草稿 --创建、更新和发送带有回复线程的草稿
- ✅ OAuth 2.1 --使用RS令牌映射保护PKCE流
- ✅ 双运行时 --Node.js/Bun或Cloudflare Workers
设计原则
- LLM友好:简化了工具,而不是1:1 Gmail API镜像
- 先发现:
inbox_overview和list_labels帮助避免猜测 - 第一批:
modify_thread接受数组以最小化工具调用 - 更安全的写作:先起草,明确发送
- 清晰的反馈:总结结构化内容和下一步行动
______________________________________________________________________
安装
跑步方式(选一种)
- 本地+OAuth (推荐)
- Cloudflare Worker(牧者开发) --本地工人测试
- Cloudflare Worker(部署) --远程生产
______________________________________________________________________
1.本地+OAuth(推荐)
- 首选 谷歌云控制台
- 创建项目并启用 Gmail API
- 创建 OAuth 2.0客户端ID (Web应用程序)
- 设置重定向URI:
http://127.0.0.1:3001/oauth/callback
alice://oauth/callback- 复制客户端ID和密码
cd gmail-mcp
bun install
cp env.example .env编辑 .env:
PORT=3000
AUTH_ENABLED=true
AUTH_STRATEGY=oauth
PROVIDER_CLIENT_ID=your-client-id.apps.googleusercontent.com
PROVIDER_CLIENT_SECRET=your-client-secret
PROVIDER_ACCOUNTS_URL=https://accounts.google.com
OAUTH_AUTHORIZATION_URL=https://accounts.google.com/o/oauth2/v2/auth
OAUTH_TOKEN_URL=https://oauth2.googleapis.com/token
OAUTH_REVOCATION_URL=https://oauth2.googleapis.com/revoke
OAUTH_SCOPES=https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.modify
OAUTH_REDIRECT_URI=alice://oauth/callback
OAUTH_REDIRECT_ALLOWLIST=alice://oauth/callback,http://127.0.0.1:3001/oauth/callback
OAUTH_EXTRA_AUTH_PARAMS=access_type=offline&prompt=consent运行:
bun dev
# MCP: http://127.0.0.1:3000/mcp
# OAuth: http://127.0.0.1:3001提示: 授权服务器在PORT+1上运行。
______________________________________________________________________
2.Cloudflare Worker(本地开发人员)
bun x wrangler secret put PROVIDER_CLIENT_ID
bun x wrangler secret put PROVIDER_CLIENT_SECRET
bun x wrangler dev --local | cat端点: http://127.0.0.1:8787/mcp
______________________________________________________________________
3.Cloudflare Worker(部署)
- 创建KV命名空间:
bun x wrangler kv:namespace create TOKENS- 更新
wrangler.toml具有KV命名空间ID
- 设置秘密:
bun x wrangler secret put PROVIDER_CLIENT_ID
bun x wrangler secret put PROVIDER_CLIENT_SECRET
# Generate encryption key (32-byte base64url):
openssl rand -base64 32 | tr -d '=' | tr '+/' '-_'
bun x wrangler secret put RS_TOKENS_ENC_KEY注: RS_TOKENS_ENC_KEY 加密存储在KV中的OAuth令牌(AES-256-GCM)。- 更新重定向URI并在中分配列表
wrangler.toml
- 将Workers URL添加到Google OAuth应用程序的重定向URI中
- 部署:
bun x wrangler deploy端点: https://..workers.dev/mcp
______________________________________________________________________
客户端配置
MCP检查员(快速测试):
bunx @modelcontextprotocol/inspector
# Connect to: http://localhost:3000/mcp克劳德桌面/光标:
{
"mcpServers": {
"gmail": {
"command": "bunx",
"args": ["mcp-remote", "http://127.0.0.1:3000/mcp", "--transport", "http-only"],
"env": { "NO_PROXY": "127.0.0.1,localhost" }
}
}
}对于Cloudflare,将URL替换为 https://..workers.dev/mcp.
______________________________________________________________________
工具
get_profile
获取已连接的Gmail帐户电子邮件。致电确认哪个帐户处于活动状态。
// Input
{}
// Output
{ email: "user@gmail.com" }inbox_overview
获取一段时间内的收件箱统计数据+亮点。 先叫这个 快速总结。
// Input
{
days?: number; // 1-365, default: 7
}
// Output
{
period: "last 7 days",
counts: { total, unread, inbox, sent, starred, important? },
highlights?: {
recentUnread: Array,
starred: Array
},
meta?: { nextSteps? }
}list_labels
发现标签ID和名称。在按标签筛选之前使用。
// Input
{}
// Output
{
items: Array,
meta?: { nextSteps?, relatedTools? }
}search_threads
使用Gmail查询语法搜索线程。返回丰富的结果。
// Input
{
query?: string; // Gmail search: "from:alice newer_than:7d"
labelIds?: string[];
includeSpamTrash?: boolean;
limit?: number; // 1-50, default: 25
cursor?: string;
}
// Output
{
items: Array,
pagination?: { hasMore, nextCursor?, itemsReturned, limit },
meta?: { nextSteps?, hints?, relatedTools? }
}get_thread
获取包含所有消息的完整帖子。
// Input
{
threadId: string;
format?: "minimal" | "metadata" | "full" | "raw";
metadataHeaders?: string[];
maxBodyChars?: number;
}
// Output
{
thread: { id, historyId?, messageCount, messages: [...], webUrl? },
meta?: { nextSteps?, relatedTools? }
}get_message
获取包含完整内容的单个消息。
// Input
{
messageId: string;
format?: "minimal" | "metadata" | "full" | "raw";
metadataHeaders?: string[];
maxBodyChars?: number;
}
// Output
{
message: { id, threadId?, snippet?, headers?, body?, webUrl? },
meta?: { nextSteps?, relatedTools? }
}modify_thread
批量添加/删除螺纹上的标签(最多100个)。支持便利操作。
// Input
{
threadIds: string[]; // 1-100 thread IDs
addLabelIds?: string[];
removeLabelIds?: string[];
actions?: {
archive?: boolean; // Remove INBOX
unarchive?: boolean; // Add INBOX
markRead?: boolean; // Remove UNREAD
markUnread?: boolean; // Add UNREAD
star?: boolean; // Add STARRED
unstar?: boolean; // Remove STARRED
trash?: boolean;
untrash?: boolean;
};
}
// Output
{
results: Array,
summary: { total, succeeded, failed },
applied: { addLabelIds?, removeLabelIds? },
meta?: { nextSteps?, relatedTools? }
}create_draft
从结构化字段或原始MIME创建草稿。
// Input
{
to?: string | string[]; // Required unless raw provided
cc?: string | string[];
bcc?: string | string[];
subject?: string;
text?: string;
html?: string;
threadId?: string; // For replies
inReplyTo?: string; // Message-ID for threading
raw?: string; // base64url RFC 2822
}
// Output
{
draft: { id, messageId?, threadId?, snippet? },
meta?: { nextSteps?, relatedTools? }
}update_draft
替换草稿的内容(Gmail草稿在内部是不可变的)。
// Input
{
draftId: string;
to?: string | string[];
cc?: string | string[];
bcc?: string | string[];
subject?: string;
text?: string;
html?: string;
threadId?: string;
raw?: string;
}send_draft
发送草稿。发送前可选择更新它。
// Input
{
draftId: string;
to?: string | string[]; // Override before send
cc?: string | string[];
bcc?: string | string[];
subject?: string;
text?: string;
html?: string;
threadId?: string;
raw?: string;
}
// Output
{
sent: { id, threadId?, labelIds?, snippet?, webUrl? },
meta?: { nextSteps?, relatedTools? }
}______________________________________________________________________
例子
1.获取收件箱摘要
{ "name": "inbox_overview", "arguments": { "days": 7 } }答复:
Inbox (last 7 days): 42 unread, 156 inbox, 12 sent, 3 starred
Recent unread:
Alice: Meeting tomorrow at 3pm
GitHub: PR merged in project-x
Starred:
Boss: Q4 Planning document2.搜索发件人的未读电子邮件
{
"name": "search_threads",
"arguments": {
"query": "from:alice@example.com is:unread newer_than:7d",
"limit": 10
}
}3.阅读帖子
{
"name": "get_thread",
"arguments": {
"threadId": "19be18067165251d",
"format": "full"
}
}4.存档多个线程
{
"name": "modify_thread",
"arguments": {
"threadIds": ["19be18067165251d", "19be17f8a2c3b4d5"],
"actions": { "archive": true, "markRead": true }
}
}答复:
Modified 2/2 threads. -INBOX -UNREAD5.回复一个帖子(先起草)
{
"name": "create_draft",
"arguments": {
"threadId": "19be18067165251d",
"to": "alice@example.com",
"text": "Thanks, I'll be there!"
}
}{
"name": "send_draft",
"arguments": { "draftId": "r8651610029774" }
}______________________________________________________________________
HTTP端点
| 端点 | 方法 | 目的 |
|---|---|---|
/mcp | 发布 | MCP JSON-RPC 2.0 |
/mcp | GET | SSE流(仅限Node.js) |
/health | GET | 健康检查 |
/.well-known/oauth-authorization-server | GET | OAuth AS元数据 |
/.well-known/oauth-protected-resource | GET | OAuth RS元数据 |
OAuth(节点端口+1):
GET /authorize--启动OAuth流GET /oauth/callback--提供商回调POST /token--代币兑换POST /revoke--撤销代币
______________________________________________________________________
发展
bun dev # Start with hot reload
bun run typecheck # TypeScript check
bun run lint # Lint code
bun run build # Production build
bun start # Run production______________________________________________________________________
建筑
src/
├── shared/
│ ├── tools/
│ │ └── gmail/ # Gmail tools (shared for Node + Workers)
│ │ ├── get-profile.ts
│ │ ├── inbox-overview.ts
│ │ ├── list-labels.ts
│ │ ├── search-threads.ts
│ │ ├── get-thread.ts
│ │ ├── get-message.ts
│ │ ├── modify-thread.ts
│ │ ├── create-draft.ts
│ │ ├── update-draft.ts
│ │ └── send-draft.ts
│ ├── oauth/ # OAuth flow (PKCE, discovery)
│ └── storage/ # Token storage (file, KV, memory)
├── services/
│ └── gmail.ts # Gmail API client
├── schemas/
│ ├── inputs.ts # Zod input schemas
│ └── outputs.ts # Zod output schemas
├── config/
│ └── metadata.ts # Server + tool descriptions
├── index.ts # Node.js entry
└── worker.ts # Workers entry______________________________________________________________________
故障排除
| 问题 | 解决方案 |
|---|---|
| “未经授权” | 再次完成OAuth流程;刷新令牌可能会被撤销。 |
| “无效凭据” | 确保OAUTH_SCOPES与您的Google应用程序和用户同意相匹配。 |
| “权限不足” | 添加 gmail.modify 范围 modify_thread. |
| “超过速率限制” | 减慢请求速度;使用较小的限制。 |
| “找不到线程” | 线程ID过期;再次搜索以获取新的ID。 |
| 草稿更新失败 | 草稿是不可变的;更新会替换底层消息。 |
| OAuth未启动(Worker) | curl -i -X POST https:///mcp 应该返回401 WWW-Authenticate. |
| 空搜索结果 | 检查查询语法;使用 list_labels 以验证标签ID。 |
| KV命名空间错误 | 运行 wrangler kv:namespace create TOKENS 并更新wrangler.toml。 |
______________________________________________________________________
许可证
麻省理工学院
