Skip to main content
Glama
micahyee415
by micahyee415

google-workspace-admin-mcp

A create-only Google Workspace admin MCP server for employee onboarding — availability checks, account creation, and credentials delivery behind Google OAuth, a per-user allowlist, and keyless domain-wide delegation.

Overview

google-workspace-admin-mcp exposes a deliberately narrow slice of the Google Workspace Admin SDK as Model Context Protocol (MCP) tools, so an AI onboarding agent (e.g. Claude) can provision new-hire accounts without ever holding broad admin rights. The surface is create-only by design — there are no delete, suspend, or update tools — and temporary passwords are generated server-side and never appear in tool results or logs.

It is built with the official @modelcontextprotocol/sdk, runs as a stateless HTTP service on Cloud Run, restricts access to a configurable Google Workspace domain plus a per-user allowlist, and reaches the Admin SDK through keyless domain-wide delegation (no service-account key ever touches disk).

Related MCP server: Google Workspace MCP

MCP Tools

Tool

Description

check_email_availability

Verifies a proposed address is free in both Google Workspace and the full Slack member history (including deactivated members). Fails closed: no definitive Slack answer, no availability verdict.

create_user

Creates the Workspace account in the configured organizational unit with a server-side temporary password. Refuses any address that has ever been used, per the never-reuse rule. Capped at 3 creations per day.

send_credentials_email

Resets the account to a fresh temporary password and emails the credentials to the hire's personal address ahead of day one.

The never-reuse rule

Google Workspace frees a deleted address after ~20 days, but Slack retains deactivated members forever — which makes Slack the durable source of truth for "has this address ever been used?". src/slackCheck.ts calls users.lookupByEmail with a bot token (users:read.email scope):

  • ok: true with user.deleted: true → the address was used before (burned)

  • users_not_found → genuinely free

Fail closed: a missing token, missing scope, rate limit, or any HTTP error throws — availability is never vouched for without a successful Slack check.

Architecture

MCP client (e.g. Claude)
        │  HTTPS + Bearer token (Google OAuth)
        ▼
  Cloud Run service  (google-workspace-admin-mcp)
  ┌─────────────────────────────────────────────┐
  │  Express HTTP server                         │
  │  ├── /health              — health check     │
  │  ├── /.well-known/...     — OAuth discovery  │
  │  ├── /register            — dynamic client   │
  │  │                          registration     │
  │  └── /mcp                 — MCP endpoint     │
  │       │                                      │
  │       ├── verifyGoogleToken()                │
  │       │     • @ALLOWED_DOMAIN enforcement    │
  │       │     • ALLOWED_USERS allowlist        │
  │       │                                      │
  │       ├── Zod input validation (schemas.ts)  │
  │       ├── Guards: target OU, daily create cap│
  │       └── Audit log on every tool call       │
  └─────────────────────────────────────────────┘
        │ keyless DWD (IAM Credentials signJwt)
        ▼
  Google Admin SDK + Gmail API        Slack Web API
  (create user, send credentials)     (never-reuse check)

Key design decisions:

  • Create-only surface — the server cannot delete, suspend, or modify existing accounts. The blast radius of a compromised client is limited to creating (capped, audited) accounts.

  • Keyless domain-wide delegation — the Cloud Run service account self-signs the delegation JWT via the IAM Credentials signJwt API. No service-account key exists on disk or in the container image. The connecting user's OAuth token only proves identity; it never touches Workspace APIs.

  • Server-side temporary passwords — generated in src/tempPassword.ts and delivered only via the credentials email. They never appear in MCP responses, logs, or error messages.

  • Fail-closed availability — the Slack never-reuse check throws on any non-definitive answer, so an outage can delay onboarding but never hand out a burned address.

  • Guard rails — new users land in a configurable organizational unit, creations are capped per day, and Zod schemas validate every tool input at the MCP boundary.

  • Rate limiting — 60 requests/min per user on the MCP endpoint; 512 KB JSON body limit.

  • Audit logging — every tool call is logged with user, action, and outcome (Cloud Logging on Cloud Run).

Tech Stack

Layer

Technology

Runtime

Node.js 22 (ESM)

Language

TypeScript 5

MCP SDK

@modelcontextprotocol/sdk

HTTP server

Express 5

Google APIs

googleapis + google-auth-library (keyless DWD)

Validation

Zod 4

Tests

node:test (unit tests for every module)

Container

Docker (multi-stage)

CI

GitHub Actions (CodeQL) + Google Cloud Build (npm audit gate)

Hosting

Google Cloud Run

Getting Started

Prerequisites

  • Node.js 22+

  • A Google Workspace domain with super-admin access (to configure domain-wide delegation)

  • A GCP project with Cloud Run enabled and a Google OAuth 2.0 Web Application client

  • A Slack app bot token with the users:read.email scope (for the never-reuse check)

Install

git clone https://github.com/micahyee415/google-workspace-admin-mcp
cd google-workspace-admin-mcp
npm install

Configuration

Copy .env.example to .env and fill in the values:

cp .env.example .env

Variable

Required

Description

ALLOWED_DOMAIN

Yes

Only verified Google accounts at this domain may connect (default: example.com)

ALLOWED_USERS

No

Per-user allowlist on top of the domain check (comma-separated emails). Unset = domain check only.

DWD_SERVICE_ACCOUNT

Yes

Service account that self-signs the delegation JWT (keyless, via signJwt)

GWS_ADMIN_SUBJECT

Yes

Workspace admin user the DWD service account impersonates

GOOGLE_CLIENT_ID

Yes

GCP OAuth 2.0 client ID (per-user sign-in)

GOOGLE_CLIENT_SECRET

Yes

GCP OAuth 2.0 client secret

SLACK_BOT_TOKEN

Yes

Slack bot token for the never-reuse check (from Secret Manager on Cloud Run)

TARGET_OU

No

Organizational unit new users are created into (default: /Employees)

COMPANY_NAME

No

Display name used in the credentials email (default: Example Corp)

CREDENTIALS_FROM

No

From: address for the credentials email (default: it@<ALLOWED_DOMAIN>)

PORT

No

HTTP port (default: 8080; Cloud Run sets this automatically)

Domain-wide delegation setup: in the Google Admin console, grant the DWD service account's client ID the scopes https://www.googleapis.com/auth/admin.directory.user and https://www.googleapis.com/auth/gmail.send. In GCP, grant the Cloud Run runtime service account roles/iam.serviceAccountTokenCreator on the DWD service account.

Send-as note: if CREDENTIALS_FROM is a group address (e.g. it@your-domain.com) rather than the impersonated admin's mailbox, configure a Gmail send-as alias for that address on the impersonated admin account first — Gmail silently rewrites the From: header otherwise.

Run locally

npm run build
npm start

Run the test suite:

npm test

Deploy to Cloud Run

gcloud builds submit --config cloudbuild.yaml --project your-gcp-project

Cloud Build will:

  1. Run npm audit at high severity — fails the build if high/critical CVEs are found.

  2. Build and push the Docker image.

  3. Deploy to Cloud Run via service.yaml (environment variables and the SLACK_BOT_TOKEN Secret Manager reference are declared there).

  4. Restore the public-invoker IAM binding — gcloud run services replace resets IAM on deploy (authentication is enforced in-app via Google OAuth).

Connecting an MCP Client

Point your MCP client at the Cloud Run service URL:

https://your-service.example.com/mcp

The server implements RFC 8414 OAuth authorization server metadata and RFC 7591 dynamic client registration, so MCP clients that support these standards can auto-discover OAuth settings.

When prompted, authenticate with a Google account in the ALLOWED_DOMAIN domain. If ALLOWED_USERS is set, your email must also be on the allowlist.

Security

  • Authentication — every request requires a valid Google OAuth bearer token; only verified @ALLOWED_DOMAIN accounts (and, if set, ALLOWED_USERS members) are accepted, with audience validation against the configured OAuth client.

  • Least privilege — create-only tool surface; delegation scopes limited to admin.directory.user + gmail.send; no service-account keys anywhere.

  • Secret hygiene — temporary passwords are never returned, logged, or embedded in errors; the Slack token lives in Secret Manager, not in the image or env files.

  • Guard rails — configurable target OU, daily creation cap, Zod validation at the MCP boundary, fail-closed availability checks, CRLF header-injection guard on personal emails.

  • CORS — only https://claude.ai and https://api.claude.ai are accepted as origins.

  • Dynamic client registration caveat/register (RFC 7591) returns the configured OAuth client credentials so MCP clients can complete the Google OAuth flow; Google's registered redirect-URI allowlist is the effective security boundary. Register only trusted callback URIs on the OAuth client, and treat the client as effectively public.

  • Rate limiting — 60 requests/min per user on the MCP endpoint.

  • Security headersX-Content-Type-Options: nosniff, X-Frame-Options: DENY, Strict-Transport-Security on all responses.

  • Audit logging — every tool call is logged with the calling user, action, and result.

  • Dependency scanningnpm audit --audit-level=high gates every Cloud Build deploy; Dependabot and CodeQL run on GitHub.

License

MIT

A
license - permissive license
-
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.

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/micahyee415/google-workspace-admin-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server