Skip to main content
Glama
AngelN-Halo

Google Workspace Directory MCP

by AngelN-Halo

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 — это простой фрагмент имени/электронной почты, жёсткий максимум 20

  • google_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. Этот репозиторий не создаёт облачные ресурсы или учётные данные.

  1. Создайте выделенный проект Google Cloud для этой рабочей нагрузки.

  2. Включите Admin SDK API (admin.googleapis.com). Для первой фазы не требуется никакой другой API Google.

  3. Создайте выделенный сервисный аккаунт и включите для него делегирование на уровне домена.

  4. Создайте или выберите выделенного делегированного администратора Workspace. Узко ограниченная пользовательская роль администратора должна предоставлять:

    • Admin API > Users > Read (USERS_RETRIEVE)

    • Admin API > Organizational Units > Read (ORGANIZATION_UNITS_RETRIEVE)

  5. Назначьте эту роль во всех организационных подразделениях, которые сервис должен запрашивать. Не используйте ежедневную супер-администраторскую учётную запись.

  6. В консоли администратора откройте Security > Access and data control > API controls > Manage Domain Wide Delegation. Добавьте числовой OAuth-идентификатор клиента сервисного аккаунта, а не его адрес электронной почты.

  7. Авторизуйте точно эту область первой фазы:

    https://www.googleapis.com/auth/admin.directory.user.readonly
  8. Создайте JSON-ключ только в том случае, если метод развёртывания без ключей в настоящее время недоступен. Немедленно переместите его в каталог, контролируемый владельцем корня/развёртывания, вне этого репозитория, установите права хоста, такие как chmod 600, ограничьте обход каталога и задокументируйте владельца и график ротации. Отзовите старый ключ после протестированной ротации.

Механизм secrets в Compose монтирует файл хоста только для чтения, но не обеспечивает шифрование в состоянии покоя для этого исходного файла. Защита хранилища хоста, контроль доступа, обработка резервных копий, реагирование на инциденты и ротация остаются необходимыми. Никогда не фиксируйте, не отправляйте по электронной почте, не вставляйте в журналы и не встраивайте ключ в образ.

Конфигурация

Переменная

Обязательность

Значение

GOOGLE_SERVICE_ACCOUNT_FILE

да

Абсолютный путь внутри контейнера к смонтированному JSON-удостоверению

GOOGLE_DELEGATED_ADMIN

да

Фиксированный делегированный субъект администратора Workspace

GOOGLE_CUSTOMER_ID

да в производстве

Явный клиент Directory; my_customer разрешён только в явном тестовом режиме

GOOGLE_ALLOWED_DOMAINS

да

Разрешённые домены Workspace через запятую, принимаемые для пользователей и псевдонимов

GOOGLE_MCP_TEST_MODE

нет

Должен быть явно true для модульной/тестовой конфигурации без аутентификации шлюза

GOOGLE_MCP_GATEWAY_SECRET

да в производстве

Случайный общий секрет от доверенного шлюза; никогда не аргумент инструмента или значение журнала

GOOGLE_MCP_AUTHORIZED_USERS

да в производстве

Авторизованные личности людей через запятую

GOOGLE_MCP_GATEWAY_SECRET_HEADER

нет

Имя заголовка; по умолчанию X-MCP-Gateway-Secret

GOOGLE_MCP_IDENTITY_HEADER

нет

Имя заголовка; по умолчанию X-Authenticated-User

GOOGLE_MCP_CALLER_DOMAINS

нет

Необязательный список разрешённых доменов вызывающего; в противном случае используется GOOGLE_ALLOWED_DOMAINS

GOOGLE_MCP_HOST

нет

Адрес прослушивания; по умолчанию 0.0.0.0 в коде

GOOGLE_MCP_PORT

нет

Порт прослушивания; по умолчанию 8000

GOOGLE_MCP_LOG_LEVEL

нет

CRITICAL, ERROR, WARNING, INFO или DEBUG

AUDIT_HASH_TARGETS

нет

HMAC-псевдонимизация целей, когда true

AUDIT_HMAC_KEY

требуется для хеширования

Не менее 32 символов; также псевдонимизирует вызывающих, когда задан

GOOGLE_EXPOSE_ADMIN_FLAGS

нет

По умолчанию false; отключённые поля возвращаются как null

GOOGLE_EXPOSE_2SV_FLAGS

нет

По умолчанию true

GOOGLE_EXPOSE_LAST_LOGIN

нет

По умолчанию true

GOOGLE_EXPOSE_ORG_UNIT

нет

По умолчанию true

Нормальный запуск проверяет конфигурацию и путь к файлу учётных данных, а затем создаёт делегированные учётные данные. Он быстро завершается с ошибкой с санитизированным сообщением, если инициализация конфигурации или учётных данных не удалась. Импорты и модульные тесты не требуют учётных данных.

Сборка и запуск

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-mcp

NPM находится вне этого репозитория и не был изменён. Добавьте следующую сеть в его проект 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_infalse, потому что не существует учётной записи, из которой можно было бы вывести историю входов.

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.

Экстренный отзыв

Если есть подозрение, что шлюз, сервисный аккаунт или делегированная личность скомпрометированы:

  1. Отключите или удалите маршрут NPM.

  2. Остановите контейнер MCP.

  3. Удалите запись клиента DWD, если есть подозрение на компрометацию.

  4. Отключите или удалите ключ сервисного аккаунта.

  5. При необходимости отключите делегированного администратора.

  6. Сохраните и проверьте журналы аудита шлюза, приложения и Google.

Примечание о миграции на WIF

Интерфейс учетных данных изолирован, поэтому позже можно добавить другого поставщика, но в этом выпуске реализован и протестирован только смонтированный JSON-ключ сервисного аккаунта. Workload Identity Federation не заявляется как поддерживаемая. Для DWD WIF не обязательно является заменой JSON-ключа: создание JWT-утверждения DWD может потребовать разрешений IAM Credentials signJwt и явной логики подписания/обмена. Спроектируйте и протестируйте этот путь перед удалением поставщика JSON-ключей.

google-mcp

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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