内容
# google-mcp-rs
一款适用于 **Google Workspace** 的多租户 **Model Context Protocol** 服务器,使用 Rust 编写。围绕可流式传输的 HTTP 传输构建,支持完整的 **OAuth 2.1**,因此可以直接与 Claude.ai、Claude Code、ChatGPT 自定义连接器、Cursor 或任何支持 2025-11-25 授权规范的 MCP 客户端配合使用。
它还可以在 **单租户标准输入/输出模式** 下运行,包装为一键式 **Claude Desktop 扩展**(`.mcpb`)—— 无需 TLS 证书,无需隧道,无需网络暴露。
> **状态:** v0.8.0 — Gmail(25)+ Sheets(11)+ Drive(14)+ Docs(12)+ Calendar(14)已上线。总共 **76 个工具**,以及基于路径的 **文件交换**(按路径附加/上传/下载,无 base64)和 2 个可选的维护工具,由 `FILE_MAINTENANCE_TOOLS` 控制。Claude Desktop 捆绑包添加了第 77 个工具,即 `google_authenticate`,用于聊天中的登录。
## 为什么
官方的 Google Workspace MCP 服务器缺少基本功能(无法从中发送电子邮件)。现有的社区服务器是 Python 或单租户的。`google-mcp-rs` 旨在成为您实际部署的 Rust 服务器:
- **完整的 Gmail / Sheets / Drive / Docs / Calendar 接口** — 76 个工具,涵盖电子邮件(搜索/线程/草稿/发送/标签/组织)、电子表格(值 + 范围 + 选项卡 + 原始 batchUpdate 进行格式化/图表)、Drive(上传、下载、导出 Google Docs 为 PDF/CSV/XLSX、共享、复制、删除)、Google Docs(读取为纯文本、追加/插入/替换、原始 batchUpdate 进行格式化和结构)和 Google Calendar(日历 + 事件 CRUD、空闲/忙碌、快速添加、与会者响应、重复)。
- **设计为多租户** — 每个用户都执行自己的 Google OAuth 流程。刷新令牌使用 AES-256-GCM 加密并绑定到用户的 Google `sub`,通过 AAD。
- **正确的 OAuth 2.1 实现** — RFC 9728 受保护的资源元数据、RFC 8414 授权服务器元数据、RFC 7591 动态客户端注册、RFC 8707 受众绑定、PKCE-S256。
- **两个传输协议,一个二进制文件** — **可流式传输的 HTTP**(多租户:一个运行实例同时为多个 MCP 客户端和多个 Google 帐户服务)或 **标准输入/输出**(单租户:Claude Desktop 将其作为本地子进程启动,无 TLS 和网络连接)。参见 [快速入门 — Claude Desktop 扩展](#快速入门——Claude-Desktop-扩展)。
- **一个二进制文件,无依赖的镜像** — 小型表面,无运行时依赖。
## 架构概述
`google-mcp-rs` 扮演两个 OAuth 角色:
1. **资源服务器** — 控制 `/mcp` 并返回 `401 + WWW-Authenticate`,其中包含指向 `/.well-known/oauth-protected-resource/mcp` 的 `resource_metadata` URL。
2. **授权服务器** — 提供 `/.well-known/oauth-authorization-server`、`/oauth/register`(DCR)、`/authorize`、`/oauth/token`。MCP 客户端自行注册并从我们这里获得 MCP JWT。
由于 Google 的 OAuth 缺乏动态客户端注册且不接受任意 `aud` 声明,因此服务器在 **代理模式** 下运行:
```
MCP 客户端(Claude.ai)
│
│ 1. /mcp ─── 401 + WWW-Authenticate ───▶
│ 2. /.well-known/oauth-protected-resource/mcp
│ 3. /oauth/register ◀── mcp_client_id, mcp_client_secret
│ 4. /authorize?response_type=code&code_challenge=...&redirect_uri=...
▼
google-mcp ──── 重定向 ───▶ accounts.google.com (同意屏幕)
│
◀────── /oauth/google/callback?code=… ◀─────┘
│ (服务器存储 Google 刷新令牌,加密)
│
│ 5. 重定向到 MCP 客户端的重定向 URI,带有我们的代码
│ 6. /oauth/token (交换代码 + PKCE 校验器) ─▶ MCP JWT
▼
MCP 客户端 → /mcp Authorization: Bearer <MCP JWT>
工具调用 Gmail,带有用户存储的刷新令牌
```
状态通过单次使用的不透明令牌存储在 SQLite 中(5 分钟 TTL)。MCP JWT 签名为 HS256,绑定到用户的 Google `sub`,受众范围限定为 `${BASE_URL}/mcp`。
## 部署姿态
该服务器设计为 **在您自己的机器上自行托管** — 通常每个工作站一个实例,监听 `127.0.0.1`,同时为多个 MCP 客户端和多个 Google 帐户服务。
公共互联网部署是 **可能的** — OAuth 流、加密(AES-256-GCM with AAD-bound `sub`、Argon2id-hashed 客户端密钥、S256 PKCE、单次使用代码,5 分钟 TTL)和按租户隔离是健全的 — 但公开部署会增加攻击面,此代码库尚未涵盖:
- **/oauth/register**、**/oauth/token**、**/authorize** 或 **/mcp** 上 **无速率限制**。暴力破解和 DoS 未缓解。
- **无用户 JWT 注销。**令牌有效期为 30 天;唯一的截止点是旋转 `JWT_SECRET`,这会使所有人退出登录。
- **在 `Host: localhost` 上跳过受众绑定**,为了本地开发方便。公共实例必须强制令牌的 `aud` 声明与部署的 `BASE_URL` 匹配,而不考虑传入的 `Host`。
- **无网络出口策略**,适用于容器 — 受损的进程可以访问互联网的任何地方。
如果这些漏洞不符合您的威胁模型,请 fork 它。该架构已设置好,以便轻松添加这些功能,并且欢迎 PR。
## 快速入门 — Claude Desktop 扩展(`.mcpb`)
运行此扩展的最快方式。Claude Desktop 在本地通过标准输入/输出启动二进制文件,因此 **无需 TLS 证书,无需隧道,无需网络暴露**。适用于 macOS、Windows 和 Linux。(仅在登录时,`127.0.0.1:8433` 上的短暂侦听器会捕获 Google 的重定向;一旦流程完成或超时,它就会关闭。)
1. **下载** 最新版本的 `google-workspace-mcp.mcpb`,来自 [Releases](https://github.com/matpb/google-mcp-rs/releases)。
2. **创建您自己的 Google OAuth 客户端** — 按照 [步骤 1](#1-创建-google-oauth-客户端) 操作,并注册此重定向 URI:
```
http://localhost:8433/oauth/google/callback
```
(如果缺少此项,Google 会拒绝登录并显示 `redirect_uri_mismatch` 错误。)
3. **双击 `.mcpb` 文件。** Claude Desktop 打开安装对话框,询问您的 **Google 客户端 ID** 和 **客户端密钥** — 粘贴它们并安装。
4. 在任何聊天中,询问 Claude 运行 **`google_authenticate`** 工具。浏览器打开,您批准访问权限,就这样了。您只需执行此操作一次。
整个配置就是这样。`JWT_SECRET` 和 `STORAGE_ENCRYPTION_KEY` 在首次运行时自动生成并存储在数据库旁边,模式为 `0600` — **捆绑包中不包含密钥**。您的加密 Google 刷新令牌仅存储在您的机器上(`~/.google-mcp.db`)。
<details>
<summary><b>平台说明(未签名的二进制文件)</b></summary>
发布二进制文件 **尚未进行代码签名或公证**,因此操作系统可能会报错:
- **macOS** — 如果 Claude Desktop 无法启动服务器,请清除下载隔离区一次:
```bash
xattr -dr com.apple.quarantine ~/Library/Application\ Support/Claude/Claude\ Extensions/
```
- **Windows** — SmartScreen 可能会在运行时警告:**更多信息 → 仍然运行**。
- **端口 8433** 必须在您登录时空闲(仅用于 OAuth 回调)。如果有其他人占用它,登录将失败,并显示清晰的错误信息。
</details>
要自己构建捆绑包,或调整工具范围,请参阅 [`mcpb/README.md`](mcpb/README.md)。
## 快速入门 — HTTP 服务器(本地开发)
### 1. 创建 Google OAuth 客户端
在 [Google Cloud Console](https://console.cloud.google.com/apis/credentials) 中:
1. 选择或创建 GCP 项目。
2. 启用 **Gmail API**、**Sheets API**、**Drive API**、**Docs API** 和 **Calendar API**。
3. **OAuth 同意屏幕** → 外部,应用名称 `google-mcp`(或您希望用户看到的任意名称),用户支持电子邮件,开发者电子邮件。
4. 添加作用域:
- `openid`
- `email`
- `https://www.googleapis.com/auth/gmail.modify`
- `https://www.googleapis.com/auth/spreadsheets`
- `https://www.googleapis.com/auth/drive`
- `https://www.googleapis.com/auth/documents`
- `https://www.googleapis.com/auth/calendar`
5. 将您自己 + 任何测试用户添加到 **测试用户** 列表(直到应用获得验证,否则只有测试用户可以授权 — 参见 [注意事项](#注意事项))。
6. **凭证** → **创建凭证** → **OAuth 2.0 客户端 ID** → **Web 应用程序**。
7. 授权重定向 URI:`${BASE_URL}/oauth/google/callback`(例如 `http://localhost:8433/oauth/google/callback` 用于开发)。
8. 保存客户端 ID 和客户端密钥。
### 2. 配置服务器
```bash
cp .env.example .env
$EDITOR .env # 填写 GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET、BASE_URL
openssl rand -hex 64 # JWT_SECRET
openssl rand -base64 32 | tr '+/' '-_' | tr -d '=' # STORAGE_ENCRYPTION_KEY
```
### 3. 运行它
```bash
cargo run --release
# 或
docker compose up --build
```
服务器默认监听 `http://0.0.0.0:8433`。`/health` 返回 `ok`。`/mcp` 需要有效的 bearer 令牌。
### 4. 连接 Claude Code
为要使用的每个 Google 帐户添加一次服务器。每个条目都会触发其自己的 OAuth 流程,因此您在提示时选择匹配的 Google 帐户。
```bash
claude mcp add --transport http --scope user google-personal http://localhost:8433/mcp
claude mcp add --transport http --scope user google-work http://localhost:8433/mcp
```
然后在任何 Claude Code 会话中运行 `/mcp` 并验证每个条目。JWT 存储在 Claude Code 的凭证保险箱中;服务器是多租户的,基于 Google `sub` 进行密钥绑定,因此一个运行实例处理两个帐户。JWT 生命周期为 30 天;访问令牌每隔一小时透明地刷新一次。
对于 **Claude.ai / ChatGPT 自定义连接器 / Cursor**,请添加一个指向 `http://localhost:8433/mcp` 的自定义连接器 — 这些客户端必须支持本地环回 URL 和 MCP 2025-11-25 OAuth 流,但并非所有客户端都支持。
## 配置
| 变量 | 是否必需 | 默认值 | 用途 |
|---|---|---|---|
| `GOOGLE_CLIENT_ID` | 是 | — | 来自 GCP 控制台的 OAuth 客户端 ID |
| `GOOGLE_CLIENT_SECRET` | 是 | — | 来自 GCP 控制台的 OAuth 客户端密钥 |
| `BASE_URL` | 是 | — | 此服务器的公共 URL,用于计算重定向 URI 和 OAuth 元数据 |
| `JWT_SECRET` | 是 | — | 用于签名 MCP JWT 的 HS256 机密(32+ 字节) |
| `STORAGE_ENCRYPTION_KEY` | 是 | — | 32 字节,base64url 编码 — 加密存储令牌 |
| `DATABASE_URL` | 否 | `./google-mcp.db` | SQLite 文件路径 |
| `MCP_HOST` | 否 | `0.0.0.0` | 绑定地址 |
| `MCP_PORT` | 否 | `8433` | 监听端口 |
| `CORS_ALLOW_LOCALHOST` | 否 | `false` | 允许 `http://localhost:*` 进入 CORS(仅限开发) |
| `ENABLED_DOMAINS` | 否 | 所有五个 | 逗号分隔的 `gmail,sheets,drive,docs,calendar` 子集。过滤 MCP 工具表面和请求的 Google 作用域。未设置 = 所有五个。参见下面的 [作用域表面](#作用域表面) |
| `FILE_ROOT` | 否 | —(禁用) | 文件交换目录的绝对路径,绑定安装到容器中的相同路径。启用按路径附加/上传和 `dest_path` 保存下载而不是 base64。未设置 = 仅 base64。参见下面的 [文件处理](#文件处理-附件-上传-下载) |
| `FILE_MAINTENANCE_TOOLS` | 否 | `off` | 目录维护工具是否暴露:`off`(无)、`info`(仅 `files_info`)或 `full`(`files_info` + 删除 `files_cleanup`)。默认为关闭,因此除非您选择启用,否则不存在删除/列出工具。仅当设置 `FILE_ROOT` 时有意义。 |
| `RUST_LOG` | 否 | `google_mcp=info,rmcp=warn,reqwest=warn` | 跟踪过滤器 — 保持 `reqwest` ≤ `warn` 以避免记录包含 PII 的 URL |
## 作用域表面
默认情况下,服务器暴露所有 76 个工具,涵盖所有五个 Workspace 域,并请求 Google 的匹配作用域集。在部署只需要部分表面时,设置 `ENABLED_DOMAINS` 为逗号分隔的子集:
```bash
ENABLED_DOMAINS=gmail # 仅 Gmail:25 个工具,gmail.modify 作用域
ENABLED_DOMAINS=gmail,calendar # 电子邮件 + 日历:39 个工具
ENABLED_DOMAINS=docs,drive # 文档工作流:26 个工具
```
两个功能同时缩小:
1. **工具表面。** 只有列出的域的 `tool_router` 实现会组合到 MCP 服务器中。其他工具不会存在于此实例 — 它们不会出现在 `tools/list` 中,它们不会消耗代理上下文令牌,它们无法被调用。
2. **OAuth 作用域。** 同意屏幕要求 Google 的 `openid`、`email`,仅列出的域的作用域。授权 Gmail 部署仅请求 Gmail 作用域。域名不区分大小写并修剪空格(`Gmail`、`GMAIL`、`gmail` 都解析相同)。未设置、空或 `ENABLED_DOMAINS=` 恢复到完整表面(向后兼容)。未知域名会快速失败并显示有效列表的错误消息。
## 文件处理(附件、上传、下载)
通过 MCP 工具调用移动二进制文件意味着 base64 — 这会增加约 33% 的大小,而且更糟糕的是,整个 blob 会在两个方向通过模型的上下文。
因为此服务器设计为在 **与 MCP 客户端相同的机器上运行**,因此它提供了一个更好的路径:**共享文件系统交换**。
设置 `FILE_ROOT` 为一个目录,并将其绑定安装到容器中 **相同的绝对路径**(提供的 `docker-compose.yml` 会自动执行此操作)。然后文件工具可以按路径命名 — 字节永远不会触摸模型的上下文:
| 代替 base64… | 执行此操作 |
| --- | --- |
| 附件到本地文件 | `gmail_send attachments=[{ "path": "<FILE_ROOT>/report.pdf" }]` |
| 将电子邮件附件保存到磁盘 | `gmail_download_attachment dest_path="<FILE_ROOT>/in.pdf"` |
| 上传本地文件到 Drive | `drive_create_file path="<FILE_ROOT>/report.pdf"` |
| 将 Drive 文件下载到磁盘 | `drive_download_file dest_path="<FILE_ROOT>/out.pdf"` |
| 导出 Google 文档到磁盘 | `drive_export_file dest_path="<FILE_ROOT>/doc.pdf"` |
它还支持 **服务器端传输**,所以字节可以在 Google↔Google 而不通过模型进行往返:
| 任务 | 执行此操作 |
| --- | --- |
| 将 Drive 文件附加到电子邮件 | `gmail_send attachments=[{ "drive_file_id": "1AbC…" }]` |
| 将电子邮件附件存储到 Drive | `gmail_download_attachment to_drive_folder_id="root"` |
**安全性和语义。** 每个路径都限制在 `FILE_ROOT` — 绝对路径必须位于其下,相对路径相对于它,并且 `..`/符号链接逃脱被拒绝。`mime_type` 从文件名中推断(如果省略)。当 `FILE_ROOT` 设置时,超过 8 MB 的大下载拒绝返回内联 base64 并指向您 `dest_path`。将 `FILE_ROOT` 留空可完全禁用基于路径的交换,并且所有工具都恢复为 base64 — 因此远程部署仍然有效,只是它们支付 base64 税。
**权限。** 容器以 uid 65532 运行,因此交换目录必须是该 uid 可写的。对于一个全新的专用目录,`chmod 0777 ~/.google-mcp/exchange` 在单个用户工作站上非常简单(或在同一用户之前创建它)。服务器编写的文件将归 65532 所有。如果您将 `FILE_ROOT` 指向一个您已经拥有的目录(例如您的下载文件夹,以便您可以复制文件而不复制它们),请使用 ACL 授予容器写入访问权限,而不向世界开放它 — `setfacl -m u:65532:rwx ~/Downloads` — 或通过 `docker-compose.override.yml` 以您的 UID 运行容器(`user: "1000:1000"`,在将数据卷更改为您的 UID 之后)。**注意事项:** 您选择的目录成为 `files_cleanup` 的作用域,因此将 `FILE_ROOT` 指向您已经管理的目录意味着未经过滤的 `files_cleanup dry_run=false` 将删除其中的所有内容(除了 `keep/` 之外) — 始终先过滤并运行干燥运行。
**可发现性。** 当设置 `FILE_ROOT` 时,MCP 服务器的 `instructions`(在连接时返回)包括一个 FILE HANDLING 部分,该部分说明了实时交换路径和这些规则,因此任何调用代理都可以在不被告知的情况下了解协议。
**保持整洁。** 交换目录随时间累积。两个可选工具可以管理它 — **默认关闭**,并且由 `FILE_MAINTENANCE_TOOLS` 控制(`off` / `info` / `full`),因此除非您选择启用,否则不会存在删除工具。永远不会自动删除任何内容。
| 工具 | 需要 | 用途 |
| --- | --- | --- |
| `files_info` | `FILE_MAINTENANCE_TOOLS=info` 或 `full` | 报告交换路径、文件数量、总字节数和一个列表(按时间倒序)。只读。 |
| `files_cleanup` | `FILE_MAINTENANCE_TOOLS=full` | 按年龄 (`older_than_hours`) 和/或名称 (`name_contains`) 删除文件。 **默认为 `dry_run: true`** — 报告将删除的内容,但不删除任何内容,直到您传递 `dry_run: false`。 |
任何位于 `FILE_ROOT` 子目录下的 `keep/` 目录中的内容都不会被 `files_cleanup` 看见,也永远不会被删除。如果您将 `FILE_ROOT` 指向一个您自己管理的目录(例如您的下载文件夹),请保持 `FILE_MAINTENANCE_TOOLS=off`(默认值),这样服务器就永远不会删除该目录中的任何内容。
### Gmail (25)
| 工具 | 用途 |
|---|---|
| `gmail_search_threads` | 使用 Gmail 查询语法搜索线程 |
| `gmail_get_thread` | 获取一个线程,包含所有消息和完整有效载荷 |
| `gmail_get_message` | 按 ID 获取单个消息 |
| `gmail_list_messages` | 列出消息,可选查询 |
| `gmail_list_attachments` | 列出消息的附件 |
| `gmail_download_attachment` | 按 ID 下载附件(返回 base64) |
| `gmail_get_thread_url` | 为线程构建 Gmail 网页 URL |
| `gmail_create_draft` | 创建草稿(可选作为回复) |
| `gmail_get_draft` | 按 ID 获取草稿 |
| `gmail_list_drafts` | 列出草稿 |
| `gmail_update_draft` | 更新现有草稿 |
| `gmail_delete_draft` | 删除草稿 |
| `gmail_send_draft` | 发送之前创建的草稿 |
| `gmail_send` | 发送电子邮件(带有 `reply_to_message_id`、`cc`、`bcc`、附件) |
| `gmail_list_labels` | 列出所有标签 |
| `gmail_get_label` | 按 ID 获取标签,包含消息数 |
| `gmail_create_label` | 创建标签(可选颜色) |
| `gmail_update_label` | 重命名或重新设置标签样式 |
| `gmail_delete_label` | 删除标签 |
| `gmail_modify_labels` | 在消息或线程上添加/删除标签 |
| `gmail_mark_read` | 将消息标记为已读 |
| `gmail_mark_unread` | 将消息标记为未读 |
| `gmail_archive` | 存档消息 |
| `gmail_trash` | 将消息移至垃圾箱 |
| `gmail_get_profile` | 返回连接账户的电子邮件和授予的范围 |
### Sheets (11)
| 工具 | 用途 |
|---|---|
| `sheets_create` | 创建新的电子表格(可选命名选项卡 + 区域设置 + 时区) |
| `sheets_get` | 获取电子表格的元数据(或带有单元格数据的特定 A1 范围) |
| `sheets_get_values` | 从 A1 范围读取值 |
| `sheets_batch_get_values` | 一次调用中从多个 A1 范围读取值 |
| `sheets_update_values` | 将 2D 值数组写入范围(`RAW` 或 `USER_ENTERED`) |
| `sheets_append_values` | 在表格形状范围内追加行 |
| `sheets_clear_values` | 清除范围中的值(保留格式) |
| `sheets_batch_update_values` | 在一次 API 调用中写入多个范围 |
| `sheets_batch_update` | 模式级批量更新 — 添加/删除工作表、格式、条件格式、图表、带状(原始 `requests[]` 直通) |
| `sheets_add_sheet` | 便捷:添加新选项卡 |
| `sheets_delete_sheet` | 便捷:按 `sheetId` 删除选项卡 |
### Docs (12)
**读取和基本写入:**
| 工具 | 用途 |
|---|---|
| `docs_create` | 创建带有标题的空 Google 文档 |
| `docs_get` | 获取文档的完整结构化有效载荷(段落、运行、表格、列表、标题、页脚、样式) |
| `docs_get_text` | 获取文档并将其正文作为 **扁平纯文本** 返回 — 代理读取内容的实用工具 |
| `docs_append_text` | 在文档末尾追加纯文本 |
| `docs_insert_text` | 在特定字符索引处插入纯文本 |
| `docs_replace_text` | 查找字符串的每个出现并替换它(可选大小写敏感) |
**格式设置助手** (隐藏索引/模式数学运算):
| 工具 | 用途 |
|---|---|
| `docs_insert_styled` | 插入带有 **文本样式** (粗体、斜体、下划线、删除线、字体大小、字体系列、前景色/背景色 `#rrggbb`、链接、基线)和/或 **段落样式** (标题 1...6、标题、副标题、普通文本)的文本。默认追加;传递 `at_index` 以获取特定位置。返回插入的范围,以便链式操作继续 |
| `docs_format_text` | 应用文本和/或段落样式。传递 **精确切片的 `range: {start_index, end_index}`** 或 **匹配的 `match: \"...\"` 以样式化每个出现** (默认为不区分大小写)。返回受影响的范围列表 |
| `docs_make_list` | 将范围内的段落转换为项目符号或编号列表。`style: \"bullet\"` (默认)或 `\"numbered\"`,或直接传递 `bullet_preset` (例如 `BULLET_CHECKBOX` 、 `NUMBERED_DECIMAL_NESTED` ) |
| `docs_insert_table` | 在位置插入空表格(`rows` × `columns`)。根据 Google 的 API 限制,最高可达 100 行 × 20 列 |
| `docs_insert_image` | 从公共 HTTPS URL 插入内联图像,可选显式 `width_pt` / `height_pt`。仅限 PNG / JPEG / GIF |
**逃生口:**
| 工具 | 用途 |
|---|---|
| `docs_batch_update` | 原始 `requests[]` 直通,用于其他所有操作(命名范围、章节换行、自定义段落间距、条件格式等) |
> **索引是 UTF-16 代码单元** (与 `docs_get` 返回的匹配)。对于 ASCII 文本,这等于字节长度;对于表情符号或非 BMP 字符,一个 Unicode 标量可以占用两个单元。
### Drive (14)
| 工具 | 用途 |
|---|---|
| `drive_list_files` | 使用 Drive 查询语法搜索/列出文件 |
| `drive_get_file` | 获取文件元数据 |
| `drive_create_folder` | 创建文件夹(可选嵌套) |
| `drive_create_file` | 上传文件(多部分,≤ ~5 MB 内容) |
| `drive_update_metadata` | 重命名、重新描述、移动(添加/删除父级)、标记 |
| `drive_update_content` | 替换文件的二进制内容 |
| `drive_download_file` | 下载字节(返回 base64) |
| `drive_export_file` | 将 Google 文档/表格/幻灯片导出为 PDF/CSV/XLSX/markdown 等 |
| `drive_copy_file` | 复制文件 |
| `drive_trash_file` | 移至回收站(可恢复) |
| `drive_delete_permanent` | **不可逆** 删除 — 优先使用 `drive_trash_file` |
| `drive_share_file` | 添加权限(用户/组/域/任何人 × 读取者/评论者/写入者/...) |
| `drive_list_permissions` | 列出共享条目 |
| `drive_delete_permission` | 按 ID 删除共享条目 |
### Calendar (14)
| 工具 | 用途 |
|---|---|
| `calendar_list_calendars` | 列出用户日历列表(主要 + 已订阅)中的日历。使用它来发现 ID |
| `calendar_get_calendar` | 获取日历的元数据(用户的“主要”日历为“primary”) |
| `calendar_create_calendar` | 创建辅助日历 |
| `calendar_delete_calendar` | **不可逆** 删除辅助日历(不能删除主要日历) |
| `calendar_list_events` | 列出/搜索事件。默认展开重复事件(`single_events=true`)。按 `time_min`/`time_max`/`q`/`updated_min` 过滤 |
| `calendar_get_event` | 按 ID 获取单个事件 |
| `calendar_create_event` | 创建具有结构化字段的事件 — 带时间(`start_date_time` + `end_date_time` RFC3339)或全天(`start_date` + `end_date`)、与会者、RRULE 重复、弹出式提醒、Google 议会链接、颜色、可见性、透明度,以及 `extra_event_fields` 逃生口 |
| `calendar_quick_add_event` | 自然语言事件创建(`明天 1 点与 Sara 共进午餐`) |
| `calendar_patch_event` | 部分更新 — 与创建相同的结构化字段,均可选。**设置 `attendees` 会替换列表** |
| `calendar_delete_event` | 删除事件(使用 `send_updates="all"` 通知与会者) |
| `calendar_move_event` | 将事件移动到不同日历 |
| `calendar_respond_to_event` | 设置用户(或另一位与会者)的 `responseStatus`:accepted / declined / tentative |
| `calendar_freebusy` | 在一段时间内查看一个或多个日历的空闲/忙碌状态 — 用于在安排前检查冲突 |
| `calendar_list_colors` | 日历 + 事件颜色调色板(用于 `colorId`) |
> **默认 `send_updates=none`。** 日历变更默认不会向与会者发送电子邮件 — 当您希望发送通知时,请显式传递 `send_updates="all"`(或 `"externalOnly"`)。
## 错误合约
服务器返回的每个错误都包含一个结构化的 `data` 有效载荷以及人类可读的 `message`。代理可以编程方式切换 `category` 和 `retryable`,而无需解析消息字符串。
```json
{
"code": -32002,
"message": "gmail message not found: 18a3b…",
"data": {
"category": "not_found",
"retryable": false,
"service": "gmail",
"http_status": 404,
"upstream_reason": "notFound",
"resource_kind": "message",
"resource_id": "18a3b…",
"hint": "Use gmail_search_threads or gmail_list_messages to discover valid message IDs."
}
}
```
| `category` | `retryable` | 何时 | 代理应执行的操作 |
|---|---|---|---|
| `invalid_input` | 否 | 工具参数格式错误(缺少字段、错误类型、互斥选项、无收件人等) | 读取 `hint`、修复参数、重试 |
| `not_found` | 否 | 资源 ID 不存在或对当前账户不可见 | 读取 `resource_kind` + `hint`、调用正确的发现工具、重试新的 ID |
| `auth_required` | 否 | 用户必须重新授权(刷新令牌被撤销、账户未在此服务器注册) | 向用户显示 `reconnect_url`;这是代理无法恢复的 |
| `auth_invalid` | 否 | JWT 本身错误(过期、错误签名、受众不匹配) | 在 `/authorize` 处重新运行 OAuth 流程 |
| `rate_limited` | **是** | 达到 Google 速率限制 | 回退(指数:250ms → 1s → 4s)并重试 |
| `permission_denied` | 否 | 账户缺乏此资源的权限 | 不重试;向用户显示 |
| `transient` | **是** | 网络闪烁 / Google 5xx | 重试一次或两次,延迟 1-5 秒 |
| `upstream` | 否 | 未分类的上游响应 | 检查 `http_status` + `message` |
| `internal` | 否 | 服务器端错误 | 重试无济于事 |
**代理恢复模式:**
- 循环使用 `gmail_send` 和格式错误的收件人 → `invalid_input` → 修复电子邮件格式、重试。
- 使用过时的 ID 调用 `gmail_get_message` → `not_found` 并且 `resource_kind: "message"` → 调用 `gmail_search_threads` 刷新、重试。
- 任意工具返回 `rate_limited` → 睡眠并重试;回退是代理的责任。
- 任意工具返回 `auth_required` 并且带有 `reconnect_url` → 要求用户重新连接 MCP 服务器;不要重试相同的工具。
## 注意事项
- **未经验证的应用上限。** 在 Google 验证您的 OAuth 客户端之前,只有 **测试用户** (在 GCP 控制台中添加)可以授权,并且应用在其生命周期内仅限 100 个用户。`gmail.modify`、`drive`、`spreadsheets`、`documents` 和 `calendar` 都是 **受限/敏感范围** — 验证完整集需要 [CASA 评估](https://cloud.google.com/security/compliance/casa) (2-6 周,加上隐私政策网址、服务条款网址、演示视频)。
- **每个 JWT 一个 Google 账户(第一阶段)。** 要使用第二个 Google 账户,请再次完成 OAuth 流程。每个工具的 `account` 参数用于在会话中切换账户,正在开发第二阶段的路线图。
- **没有发送安全旋钮。** 工具立即执行 `gmail_send`。如果您想要仅草稿模式,请不要将 `gmail_send` 暴露给代理 — 而是指向 `gmail_create_draft`。
- **MVP 中未验证 ID 令牌签名。** 服务器信任 Google 的 ID 令牌,因为通道到 Google 的令牌端点是 TLS。强化以验证 Google 的 JWKS 正在开发中。
- **刷新令牌吊销。** 如果用户在其 Google 账户中吊销应用的访问权限,则下一个工具调用将返回 `ReconnectRequired` 错误,指向 `/authorize`。
- **日志中的 PII。** 跟踪故意编辑主题、正文、收件人和搜索查询。日志仅包含结构化元数据(计数、长度、持续时间、不透明的 `sub` ID)。将 `RUST_LOG` 固定为 `reqwest` ≤ `warn`,以便请求 URL(可以携带 PII 查询参数)不被记录。
## 路线图
- **每个工具的 `account` 参数**,用于单个 MCP 会话中的多账户工作流。
- **表单、人员(联系人)、任务** — 剩余的 Workspace 界面。
- **可恢复的 Drive 上传**,适用于大于 ~5 MB 的文件。
- **强化:** ID 令牌 JWKS 验证、刷新令牌轮换、结构化每个账户审计日志。
## 贡献
欢迎拉取请求。CI 运行 `cargo fmt --check`、`cargo clippy -- -D warnings` 和 `cargo test`。请将机密信息排除在固定装置和测试之外。
## 许可证
MIT — 请参阅 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器