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)Внешний шлюз аутентифицирует человека и должен внедрять общий секрет шлюза, а также проверенную личность вызывающего. Приложение проверяет оба, авторизует личность и включает её вместе с сгенерированным идентификатором запроса в каждое событие аудита инструмента. Общий секрет доказывает, что запрос прошёл через доверенный путь входа; он не идентифицирует отдельного человека и не заменяет сетевую изоляцию или внешний TLS. NPM должен удалять копии обоих заголовков, предоставленные клиентом, перед внедрением собственных значений.
Приложение привязывается к 0.0.0.0:8000 внутри контейнера, чтобы Docker и NPM могли до него добраться. Compose публикует только 127.0.0.1:8000:8000 на хосте. Сервис Compose использует выделенную внешнюю сеть Docker с именем google-mcp-ingress; подключайте к этой сети только 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). Для первой фазы не требуется никакой другой API Google.Создайте выделенный сервисный аккаунт и включите для него делегирование на уровне домена.
Создайте или выберите выделенного делегированного администратора Workspace. Узко ограниченная пользовательская роль администратора должна предоставлять:
Admin API > Users > Read (
USERS_RETRIEVE)Admin API > Organizational Units > Read (
ORGANIZATION_UNITS_RETRIEVE)
Назначьте эту роль во всех организационных подразделениях, которые сервис должен запрашивать. Не используйте ежедневную супер-администраторскую учётную запись.
В консоли администратора откройте Security > Access and data control > API controls > Manage Domain Wide Delegation. Добавьте числовой OAuth-идентификатор клиента сервисного аккаунта, а не его адрес электронной почты.
Авторизуйте точно эту область первой фазы:
https://www.googleapis.com/auth/admin.directory.user.readonlyСоздайте JSON-ключ только в том случае, если метод развёртывания без ключей в настоящее время недоступен. Немедленно переместите его в каталог, контролируемый владельцем корня/развёртывания, вне этого репозитория, установите права хоста, такие как
chmod 600, ограничьте обход каталога и задокументируйте владельца и график ротации. Отзовите старый ключ после протестированной ротации.
Механизм secrets в Compose монтирует файл хоста только для чтения, но не обеспечивает шифрование в состоянии покоя для этого исходного файла. Защита хранилища хоста, контроль доступа, обработка резервных копий, реагирование на инциденты и ротация остаются необходимыми. Никогда не фиксируйте, не отправляйте по электронной почте, не вставляйте в журналы и не встраивайте ключ в образ.
Конфигурация
Переменная | Обязательность | Значение |
| да | Абсолютный путь внутри контейнера к смонтированному JSON-удостоверению |
| да | Фиксированный делегированный субъект администратора Workspace |
| да в производстве | Явный клиент Directory; |
| да | Разрешённые домены Workspace через запятую, принимаемые для пользователей и псевдонимов |
| нет | Должен быть явно |
| да в производстве | Случайный общий секрет от доверенного шлюза; никогда не аргумент инструмента или значение журнала |
| да в производстве | Авторизованные личности людей через запятую |
| нет | Имя заголовка; по умолчанию |
| нет | Имя заголовка; по умолчанию |
| нет | Необязательный список разрешённых доменов вызывающего; в противном случае используется |
| нет | Адрес прослушивания; по умолчанию |
| нет | Порт прослушивания; по умолчанию |
| нет |
|
| нет | HMAC-псевдонимизация целей, когда true |
| требуется для хеширования | Не менее 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 downПример клиента MCP находится в 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Живой смоук-скрипт запускается только при явном вызове. Используйте вымышленные переменные ниже в качестве заполнителей и устанавливайте реальные тестовые адреса только в оболочке, никогда в файлах:
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 возвращает ровно эти поля состояния. Подлинный 404 от Directory API — единственное условие NOT_FOUND. ARCHIVED имеет приоритет над SUSPENDED; все остальные существующие пользователи — ACTIVE. Эпохальное/сторожевое значение последнего входа Google становится null плюс never_logged_in: true. Необязательные поля остаются присутствующими как null, когда отключены. Флаги администратора по умолчанию null, если явно не раскрыты; поля 2SV, последнего входа и организационного подразделения по умолчанию раскрыты.
{
"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, — 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"
}
]
}Настроенный идентификатор клиента всегда используется. Результаты за пределами разрешённых доменов опускаются и делают truncated истинным. Токен страницы вышестоящего сервиса никогда не раскрывается; вызывающие должны сузить термин, когда truncated или next_page_available истинны. Термины должны быть длиной 3..128 символов и не содержать управляющих/форматных символов или необработанного синтаксиса запросов. Пределы вне 1..20 отклоняются, и запрашивается только одна вышестоящая страница.
Журналирование и поведение при сбоях
Каждый вызов инструмента создает одно структурированное JSON-событие аудита, содержащее временную метку UTC, сгенерированный идентификатор запроса, подтвержденную личность вызывающего (или 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: используйте числовой OAuth-идентификатор клиента сервисного аккаунта в DWD и авторизуйте точную область действия, указанную выше. Изменения DWD могут распространяться не сразу.403/AUTHORIZATION: проверьте права Users Read и Organizational Units Read, область назначения OU, контроль доступа к API, делегированного субъекта и Admin SDK API. Действительного ключа недостаточно.Отсутствующая область: сравните запись DWD посимвольно с
https://www.googleapis.com/auth/admin.directory.user.readonly. Первый этап намеренно не запрашивает области групп, Drive, Gmail, Calendar, управления ролями или управления безопасностью.Неверный делегированный субъект: исправьте
GOOGLE_DELEGATED_ADMIN; это должен быть выделенный делегированный администратор, чья роль охватывает запрашиваемые OU. Вызывающий MCP не может это переопределить.Расхождение часов: синхронизируйте часы хоста Docker. Подписанные JWT-утверждения чувствительны ко времени.
Неожиданный
NOT_FOUND: убедитесь, что запрошенный адрес электронной почты использует настроенный разрешенный домен и является текущим неудаленным пользователем Directory. Ошибки авторизации и ограничения частоты запросов никогда не становятсяNOT_FOUND.
Экстренный отзыв
Если есть подозрение, что шлюз, сервисный аккаунт или делегированная личность скомпрометированы:
Отключите или удалите маршрут NPM.
Остановите контейнер MCP.
Удалите запись клиента DWD, если есть подозрение на компрометацию.
Отключите или удалите ключ сервисного аккаунта.
При необходимости отключите делегированного администратора.
Сохраните и проверьте журналы аудита шлюза, приложения и Google.
Примечание о миграции на WIF
Интерфейс учетных данных изолирован, поэтому позже можно добавить другого поставщика, но в этом выпуске реализован и протестирован только смонтированный JSON-ключ сервисного аккаунта. Workload Identity Federation не заявляется как поддерживаемая. Для DWD WIF не обязательно является заменой JSON-ключа: создание JWT-утверждения DWD может потребовать разрешений IAM Credentials signJwt и явной логики подписания/обмена. Спроектируйте и протестируйте этот путь перед удалением поставщика JSON-ключей.
google-mcp
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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).14MIT
- AlicenseNot gradedqualityCmaintenanceAn 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.12MIT
Related MCP Connectors
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Federated commerce search across independent WooCommerce merchants. Keyless, read-only MCP server.
Identity resolution MCP server for phone/email lookups across 31+ services. Global + India coverage.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AngelN-Halo/google-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server