google-workspace-admin-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@google-workspace-admin-mcpCheck if jane.doe@company.com is available for a new hire"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| 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. |
| 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. |
| 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: truewithuser.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
signJwtAPI. 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.tsand 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 |
|
HTTP server | Express 5 |
Google APIs |
|
Validation | Zod 4 |
Tests |
|
Container | Docker (multi-stage) |
CI | GitHub Actions (CodeQL) + Google Cloud Build ( |
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.emailscope (for the never-reuse check)
Install
git clone https://github.com/micahyee415/google-workspace-admin-mcp
cd google-workspace-admin-mcp
npm installConfiguration
Copy .env.example to .env and fill in the values:
cp .env.example .envVariable | Required | Description |
| Yes | Only verified Google accounts at this domain may connect (default: |
| No | Per-user allowlist on top of the domain check (comma-separated emails). Unset = domain check only. |
| Yes | Service account that self-signs the delegation JWT (keyless, via |
| Yes | Workspace admin user the DWD service account impersonates |
| Yes | GCP OAuth 2.0 client ID (per-user sign-in) |
| Yes | GCP OAuth 2.0 client secret |
| Yes | Slack bot token for the never-reuse check (from Secret Manager on Cloud Run) |
| No | Organizational unit new users are created into (default: |
| No | Display name used in the credentials email (default: |
| No | From: address for the credentials email (default: |
| No | HTTP port (default: |
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 startRun the test suite:
npm testDeploy to Cloud Run
gcloud builds submit --config cloudbuild.yaml --project your-gcp-projectCloud Build will:
Run
npm auditathighseverity — fails the build if high/critical CVEs are found.Build and push the Docker image.
Deploy to Cloud Run via
service.yaml(environment variables and theSLACK_BOT_TOKENSecret Manager reference are declared there).Restore the public-invoker IAM binding —
gcloud run services replaceresets 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/mcpThe 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_DOMAINaccounts (and, if set,ALLOWED_USERSmembers) 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.aiandhttps://api.claude.aiare 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 headers —
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Strict-Transport-Securityon all responses.Audit logging — every tool call is logged with the calling user, action, and result.
Dependency scanning —
npm audit --audit-level=highgates every Cloud Build deploy; Dependabot and CodeQL run on GitHub.
License
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.
Latest Blog Posts
- 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/micahyee415/google-workspace-admin-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server