Google Workspace Directory MCP
Google Workspace Directory MCP
面向生产环境、只读的 MCP 服务,用于范围受限的 Google Workspace 用户查询。它使用 Python、FastMCP Streamable HTTP、Google Admin SDK Directory API、专用服务账号 JSON 凭据、域级委派(DWD)以及来自服务器配置的一个固定委派管理员主体。
该服务仅执行 users.get 和 users.list。它不能创建、更新、暂停、归档、重命名、删除或以其他方式修改用户。
架构与威胁边界
MCP client
-> external TLS and human authentication at Nginx Proxy Manager
-> dedicated ingress network + gateway secret and verified identity headers
-> FastMCP /mcp on 0.0.0.0:8000
-> fixed-subject DWD credential provider
-> Google Admin SDK Directory API (read-only users scope)外部网关对人员进行身份验证,并且必须注入共享网关密钥以及经过验证的调用者身份。应用会验证两者,对身份进行授权,并在每次工具审计事件中将其与生成的请求 ID 一起包含。共享密钥证明请求来自可信的入口路径;它不标识个人,也不能替代网络隔离或外部 TLS。NPM 必须在注入自己的值之前移除客户端提供的这两个请求头副本。
应用在容器内绑定到 0.0.0.0:8000,以便 Docker 和 NPM 可以访问它。Compose 仅在主机上发布 127.0.0.1:8000:8000。Compose 服务使用名为 google-mcp-ingress 的专用外部 Docker 网络;只将 NPM 和此服务附加到该网络。不要使用通用 proxy 网络。
MCP 进程验证输入和允许的电子邮件域,从普通搜索词构造有界的 Google 查询,限制搜索输出,请求部分响应字段,过滤跨域别名,从目录文本中移除控制/格式字符,并返回窄而稳定的模式。目录文本是不可信数据,并在 MCP 服务器/工具指令中明确标记为不可信;客户端不得将名称、别名、路径或查询视为指令。这是信任边界控制,不能替代 MCP 客户端系统级的提示注入防御。
DWD 功能强大:Google 授权 OAuth 客户端和范围,但不强制执行此应用的固定主体选择。持有服务账号私钥的人可以编写不同的代码,选择 DWD 允许的另一个主体。此服务在配置中固定 GOOGLE_DELEGATED_ADMIN,并且绝不接受主体作为工具参数,但这是应用控制,而不是 Google 强制的主体限制。
Related MCP server: gwsadm-mcp
第一阶段工具
google_user_status(email)google_user_search(query, limit=10);query是普通名称/电子邮件片段,硬性上限20google_user_aliases(email)google_user_summary(email)
每个显式电子邮件参数必须属于 GOOGLE_ALLOWED_DOMAINS 之一,不区分大小写比较。返回的别名列表仅包含这些域。辅助 Workspace 域必须显式列出。该服务绝不跟随别名进入另一个域。
已计划但未实现:
google_user_groups(email)需要额外的范围https://www.googleapis.com/auth/admin.directory.group.readonly。
第一阶段不包含任何组范围或组 API 操作。
Google 前置条件
这些是手动的 Google 管理步骤。本仓库不创建云资源或凭据。
为此工作负载创建专用的 Google Cloud 项目。
启用 Admin SDK API(
admin.googleapis.com)。第一阶段不需要其他 Google API。创建专用服务账号并为其启用域委派。
创建或选择专用的 Workspace 委派管理员用户。范围狭窄的自定义管理员角色应授予:
Admin API > Users > Read(
USERS_RETRIEVE)Admin API > Organizational Units > Read(
ORGANIZATION_UNITS_RETRIEVE)
在服务要查询的每个 OU 中分配该角色。不要使用日常超级管理员账号。
在 Admin 控制台中,打开 Security > Access and data control > API controls > Manage Domain Wide Delegation。添加服务账号的 数字 OAuth 客户端 ID,而不是其电子邮件地址。
仅授权此第一阶段范围:
https://www.googleapis.com/auth/admin.directory.user.readonly仅当当前没有无密钥部署方法时才创建 JSON 密钥。立即将其移动到本仓库之外的根/部署所有者控制的目录,设置主机权限(如
chmod 600),限制目录遍历,并记录所有者和轮换计划。经过测试的轮换后撤销旧密钥。
Compose secrets 机制以只读方式挂载主机文件,但不为该源文件提供静态加密。主机存储保护、访问控制、备份处理、事件响应和轮换仍然是必要的。切勿提交、通过电子邮件发送、粘贴到日志中或将密钥烘焙到镜像中。
配置
变量 | 必需 | 含义 |
| 是 | 容器内挂载的 JSON 凭据的绝对路径 |
| 是 | 固定的委派 Workspace 管理员主体 |
| 生产环境中是 | 显式 Directory 客户; |
| 是 | 逗号分隔的 Workspace 域,接受用户和别名 |
| 否 | 必须显式为 |
| 生产环境中是 | 来自可信网关的随机共享密钥;绝不可作为工具参数或日志值 |
| 生产环境中是 | 逗号分隔的授权人员身份 |
| 否 | 标头名称;默认为 |
| 否 | 标头名称;默认为 |
| 否 | 可选的调用者域允许列表;否则使用 |
| 否 | 监听地址;代码中默认为 |
| 否 | 监听端口;默认为 |
| 否 |
|
| 否 | 为 true 时对目标进行 HMAC 假名化 |
| 哈希必需 | 至少 32 个字符;设置时也会对调用者进行假名化 |
| 否 | 默认为 |
| 否 | 默认为 |
| 否 | 默认为 |
| 否 | 默认为 |
正常启动会验证配置和凭据文件路径,然后构造委派凭据。如果配置或凭据初始化失败,它会快速失败并返回经过清理的错误。导入和单元测试不需要凭据。
构建和运行
cd google-mcp
cp .env.example .env
chmod 600 .env
# Edit .env; the host credential path must remain outside this repository.
docker compose config
docker compose build
docker compose up -d本地端点为 http://127.0.0.1:8000/mcp;NPM 应通过专用入口网络使用 http://google-mcp:8000/mcp。在不暴露机密的情况下检查启动:
docker compose ps
docker compose logs --tail=100 google-mcpNPM 位于本仓库之外,未被修改。将以下网络添加到其 Compose 项目中,将 app 附加到它,并在启动两个项目之前创建网络:
services:
app:
networks:
- proxy
- google-mcp-ingress
networks:
google-mcp-ingress:
external: true
name: google-mcp-ingress然后创建一个经过身份验证的 NPM 代理主机,转发到主机名 google-mcp、端口 8000 和路径 /mcp。Streamable HTTP 需要同时转发 POST 和 GET,保留 /mcp 路径而不重写,禁用响应缓冲,并使用足够长的读取/发送超时。示例 NPM 高级配置,仅使用占位符:
proxy_http_version 1.1;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_set_header Connection "";
proxy_set_header X-MCP-Gateway-Secret "REPLACE_WITH_SECRET_FROM_NPM_SECRET_STORE";
proxy_set_header X-Authenticated-User $remote_user;NPM 必须覆盖这些标头,而不是传递客户端值。如果选定的 NPM 认证机制不填充 $remote_user,请使用提供已验证身份标头的 SSO/认证代理;不要将共享网关密钥视为个人调用者身份。不要启用宽松的 CORS。
如果专用网络尚不存在,请在启动任一 Compose 项目之前创建它:
docker network create google-mcp-ingress停止并移除容器/网络,同时保留外部凭据文件:
docker compose downMCP 客户端示例位于 examples/mcp-client.json。其 URL、主机名和令牌是占位符。根据特定客户端和认证网关调整形状。
测试
单元测试模拟 Directory API,绝不联系 Google:
cd google-mcp
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements-dev.txt
pytest -q容器化测试路径避免主机 Python 依赖假设:
docker build --target test -t google-mcp:test .
docker run --rm --user "$(id -u):$(id -g)" --read-only --tmpfs /tmp:size=16m \
-v "$PWD/tests:/app/tests:ro" \
google-mcp:test pytest -q -p no:cacheprovider实时冒烟脚本仅在显式调用时运行。使用以下虚构变量作为占位符,并仅在 shell 中设置真实测试地址,绝不在文件中设置:
export GOOGLE_TEST_USER='known-active-user@example.test'
export GOOGLE_TEST_MISSING_USER='known-missing-user@example.test' # optional
export GOOGLE_TEST_GATEWAY_SECRET='set-only in the shell; never in a file' # required outside test mode
export GOOGLE_TEST_CALLER='agent1@example.org' # required outside test mode
python tests/smoke_mcp.py http://127.0.0.1:8000/mcp它确认精确的第一阶段工具列表,要求已知用户返回 ACTIVE,可选地要求缺失用户返回 NOT_FOUND,并且仅打印状态——不打印完整的用户记录。
稳定的响应模式
google_user_status 仅返回这些状态字段。真正的 Directory API 404 是唯一的 NOT_FOUND 条件。ARCHIVED 优先于 SUSPENDED;所有其他现有用户均为 ACTIVE。Google 的纪元/哨兵最后登录值变为 null 加上 never_logged_in: true。可选字段在禁用时保持为 null。管理员标志默认为 null,除非显式暴露;2SV、最后登录和 OU 字段默认为暴露。
{
"email": "alex.rivera@example.test",
"state": "ACTIVE",
"suspended": false,
"archived": false,
"last_login_time": "2026-08-01T13:45:00.000Z",
"never_logged_in": false,
"org_unit_path": "/Staff/Campus-A",
"is_admin": null,
"is_delegated_admin": null,
"is_enrolled_in_2sv": true,
"is_enforced_in_2sv": true
}对于 NOT_FOUND,布尔字段为 false,可空字段为 null,never_logged_in 为 false,因为不存在可以推断登录历史的账号。
google_user_aliases:
{
"email": "alex.rivera@example.test",
"state": "ACTIVE",
"primary_email": "alex.rivera@example.test",
"aliases": ["a.rivera@example.test"],
"non_editable_aliases": ["alex@example.test"]
}google_user_summary 包含所有状态字段加上 requested_email、display_name、given_name、family_name、aliases 和 non_editable_aliases。它使用一次 users.get 调用。
google_user_search 接受普通人工输入的片段,而不是 Google Directory 查询语法。它安全地构造电子邮件前缀/名称前缀查询或精确的允许域电子邮件查询。
google_user_search:
{
"query": "Alex Rivera",
"limit": 10,
"count": 1,
"truncated": false,
"next_page_available": false,
"users": [
{
"email": "alex.rivera@example.test",
"display_name": "Alex Rivera",
"state": "ACTIVE",
"suspended": false,
"archived": false,
"last_login_time": "2026-08-01T13:45:00.000Z",
"never_logged_in": false,
"org_unit_path": "/Staff/Campus-A"
}
]
}始终使用配置的客户 ID。允许域之外的结果被省略,并使 truncated 为 true。上游页面令牌永远不会暴露;当 truncated 或 next_page_available 为 true 时,调用者应缩小搜索词。搜索词必须为 3..128 个字符,并且不包含控制/格式字符或原始查询语法。超出 1..20 的限制被拒绝,并且只请求一个上游页面。
日志记录和失败行为
每次工具调用都会发出一个结构化的 JSON 审计事件,其中包含 UTC 时间戳、生成的请求 ID、已验证的调用者身份(或 HMAC 假名)、工具、被掩蔽或经 HMAC 假名化的目标、结果状态/计数、延迟以及经过清理的错误类别。该服务不会记录网关机密、访问令牌、凭据内容或路径、私钥、完整的 Google 记录、原始提示、别名、姓名、电话/个人资料数据或 Google 原始错误正文。
只有 HTTP 404 映射为 NOT_FOUND。HTTP 401/403 变为 AUTHORIZATION;429 和符合条件的 5xx(500、502、503、504)最多总共尝试四次,并采用指数退避和抖动。超时和瞬时传输故障同样有界。其他格式错误或上游故障仍保留为明确的清洗后错误。
故障排查
invalid_grant:验证被委派的主体是否存在、未被暂停、位于同一 Workspace 租户中,并且服务器时钟与 NTP 同步。同时验证该凭据是否属于已启用 DWD 的服务账号。unauthorized_client:在 DWD 中使用服务账号的数字 OAuth 客户端 ID,并授权上面显示的确切范围。DWD 更改可能需要一段时间才能生效。403/AUTHORIZATION:验证用户读取和组织单位读取权限、OU 分配范围、API 访问控制、被委派的主体以及 Admin SDK API。仅凭有效的密钥是不够的。缺少范围:将 DWD 条目与
https://www.googleapis.com/auth/admin.directory.user.readonly逐字符比对。第一阶段有意不请求任何群组、云端硬盘、Gmail、日历、角色管理或安全管理范围。被委派主体错误:更正
GOOGLE_DELEGATED_ADMIN;它必须是专用的委派管理员,其角色覆盖所查询的 OU。MCP 调用者无法覆盖它。时钟偏差:同步 Docker 主机时钟。签名的 JWT 断言对时间敏感。
意外出现
NOT_FOUND:确认请求的电子邮件使用配置的允许域,并且是当前未删除的 Directory 用户。授权和速率限制失败绝不会变为NOT_FOUND。
紧急撤销
如果怀疑网关、服务账号或委派身份遭到入侵:
禁用或移除 NPM 路由。
停止 MCP 容器。
如果怀疑入侵,请移除 DWD 客户端条目。
禁用或删除服务账号密钥。
如有需要,禁用委派管理员。
保留并审查网关、应用程序和 Google 审计日志。
WIF 迁移说明
凭据接口是隔离的,因此以后可以添加其他提供商,但此版本仅实现并测试了挂载的服务账号 JSON 密钥。Workload Identity Federation 不被声称受支持。对于 DWD,WIF 不一定是 JSON 密钥的直接替代品:生成 DWD JWT 断言可能需要 IAM Credentials signJwt 权限以及显式的签名/交换逻辑。在移除 JSON 密钥提供商之前,请设计并测试该路径。
google-mcp
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only Google Search Console MCP server for AI assistants.
1Read-only MCP server for AIStatusDashboard status, incidents, metrics, and fallback recommendations.
Read-only Google Analytics 4 MCP server for AI assistants.
1Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceRead-only MCP server for Google Merchant Center, Google Search Console, Google Drive, Gmail, Calendar, and People API.MIT
- AlicenseAqualityAmaintenanceGoogle Workspace security-audit MCP server — read-only visibility into account locks, suspicious logins, and external file sharing, built on the Admin SDK Reports API (audit activities).16126 PyPIMIT
- AlicenseNot gradedqualityBmaintenanceAn admin-oriented Model Context Protocol server for Google Workspace that lets LLMs perform directory and user lifecycle operations with safety guardrails and audit logging.MIT
- AlicenseNot gradedqualityBmaintenanceSecure, read-only Google Search Console MCP server with exact property allowlists and a hardened TypeScript runtime.15 npmMIT