gws-admin-mcp
Safe Google Workspace admin for AI agents: read-only by default, confirm-gated deletes, audit log.
Open source Open in the app JSON README (API)
About
Safe Google Workspace admin for AI agents: read-only by default, confirm-gated deletes, audit log.
Details
- Kind
- MCP servers
- Topic
- Security & identity
- Publisher
- antct11
- Origin
- official
- Category
- ferramentas
- Transport
- desconhecido
- Version
- 0.3.0
- Last push
- 2026-08-08T07:00:04Z
- Repository state
- ativo
- Language
- TypeScript
- License
- NOASSERTION
- Added
- 2026-08-29 03:02:25
- Updated
- 2026-08-29 03:02:25
- Origin id
io.github.antct11/gws-admin-mcp
README
# gws-admin-mcp
A local **Model Context Protocol (MCP) server** that gives your AI agent
(Cursor, Claude Desktop, or any MCP client) a **safe Google Workspace admin
console**. It talks to the Admin SDK (Directory, Reports, Groups Settings)
through a **service account with domain-wide delegation**, so the agent can
answer questions like "which users haven't logged in for 90 days?" or "who is
in the Finance group?" — and, only when you explicitly allow it, make changes.
```
MCP client ──stdio──► gws-admin-mcp ──service account JWT (impersonates an admin)──► admin.googleapis.com / groupssettings.googleapis.com
```
Runs entirely on your machine. No third-party service, no telemetry, no data
leaves your laptop except the Google API calls themselves.
## Safety model
This server assumes the agent driving it is fallible. Three layers:
1. **Read-only by default.** Out of the box only the 17 read tools are
registered — write tools are not hidden behind a runtime check, they simply
*do not exist* in the tool list, so the agent cannot call them. Mutations
require starting the server with `--allow-write` (or
`GWS_ADMIN_ALLOW_WRITE=1`).
2. **Confirm gate on destructive calls.** Even with writes enabled, the
irreversible operations — `users_delete`, `groups_delete`,
`orgunits_delete`, `role_assignment_delete`, mobile device *wipe* actions,
and ChromeOS *deprovision* — are refused unless the call includes
`"confirm": true`. The agent has to make the destructive intent explicit a
second time.
3. **Audit log.** Every tool call is appended as JSON lines to
`~/.config/gws-admin-mcp/audit.log` (mode 600), with passwords and secrets
redacted. Disable with `GWS_ADMIN_AUDIT=0` if you must.
Recommended pattern: run the read-only instance permanently, and start a
second, write-enabled instance only for the duration of a change window.
## Tools (40 total; 17 in read-only mode)
| Area | Read-only tools | Write tools (require `--allow-write`) |
|------|-----------------|----------------------------------------|
| **Users** | `users_list`, `users_get` | `users_create`, `users_update`, `users_suspend`, `users_unsuspend`, `users_reset_password`, `users_make_admin`, `users_move_ou`, `users_delete`* |
| **Groups** | `groups_list`, `groups_get`, `groups_list_members` | `groups_create`, `groups_update`, `groups_delete`*, `groups_add_member`, `groups_remove_member`, `groups_update_member` |
| **Org units** | `orgunits_list`, `orgunits_get` | `orgunits_create`, `orgunits_update`, `orgunits_delete`* |
| **Roles** | `roles_list`, `role_assignments_list` | `role_assignment_create`, `role_assignment_delete`* |
| **Domains / customer** | `domains_list`, `customer_get` | — |
| **Devices** | `devices_list_mobile`, `devices_list_chromeos` | `devices_action_mobile`*, `devices_action_chromeos`*, `devices_move_chromeos` |
| **Reports** | `reports_activities` (audit log), `reports_usage_user`, `reports_usage_customer` | — |
| **Group settings** | `groupsettings_get` | `groupsettings_update` |
\* Destructive — additionally requires `"confirm": true` in the call
(device tools only for wipe/deprovision actions).
List tools auto-paginate up to a `maxResults` cap, and `users_list` supports
the full Admin SDK search syntax (`orgUnitPath='/Sales'`, `isAdmin=true`,
`email:jdoe*`, ...).
## Requirements
- Node.js >= 20
- Super-admin access to a Google Workspace domain (to grant domain-wide
delegation)
- A Google Cloud project (free — the Admin SDK has no usage cost)
## Google Cloud setup
You need a service account whose key the server uses to impersonate a
Workspace super-admin. Two paths:
### Path A — scripted (needs `gcloud`)
```bash
gcloud auth login admin@yourdomain.com
scripts/setup-service-account.sh admin@yourdomain.com your-project-id
```
The script creates/reuses the project, enables the Admin SDK + Groups
Settings APIs, creates the service account, writes the key and config to
`~/.config/gws-admin-mcp/`, and prints the client ID + scope string for the
final manual step (step 5 below — Google provides no API for that part).
### Path B — manual (Cloud console)
1. **Create a project** at [console.cloud.google.com](https://console.cloud.google.com)
(or reuse one dedicated to admin tooling).
2. **Enable APIs**: *Admin SDK API* and *Groups Settings API*
(APIs & Services → Library).
3. **Create a service account** (IAM & Admin → Service Accounts → Create).
No project-level IAM roles are needed — its power comes entirely from the
delegation grant in the next steps.
4. **Create a JSON key** for it (Keys tab → Add key → JSON) and save it as
`~/.config/gws-admin-mcp/service-account.json` with `chmod 600`.
5. **Grant domain-wide delegation** — this is the step people miss:
- Copy the service account's **OAuth 2 client ID** (a long number, shown on
the service account details page).
- In the **Admin console** ([admin.google.com](https://admin.google.com)):
*Security → Access and data control → API controls → Domain-wide
delegation → Add new*.
- Paste the client ID, and paste this exact scope list as one
comma-separated line:
```
https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.orgunit,https://www.googleapis.com/auth/admin.directory.rolemanagement,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly,https://www.googleapis.com/auth/admin.directory.device.mobile,https://www.googleapis.com/auth/admin.directory.device.chromeos,https://www.googleapis.com/auth/admin.reports.audit.readonly,https://www.googleapis.com/auth/admin.reports.usage.readonly,https://www.googleapis.com/auth/apps.groups.settings
```
6. **Tell the server which admin to impersonate.** Create
`~/.config/gws-admin-mcp/config.json`:
```json
{
"delegatedAdmin": "admin@yourdomain.com",
"customerId": "my_customer"
}
```
`delegatedAdmin` must be a **super-admin** of the domain. `my_customer`
resolves to that admin's own organization.
Environment variables override the config files: `GOOGLE_SA_KEY` (key path),
`DELEGATED_ADMIN`, `CUSTOMER_ID`, `GWS_ADMIN_CONFIG_DIR` (alternate config
directory). See `.env.example`.
## Build and verify
```bash
npm install
npm run build
node dist/cli.js doctor
```
`doctor` checks the key, mints a delegated token, and runs sample reads
against users, domains, roles, and the audit reports API. All four should say
`PASS`. Then optionally:
```bash
npm run smoke # spawns the real server over stdio, checks tool registration + live reads
```
## MCP client configuration
### Cursor (`~/.cursor/mcp.json`)
Read-only — the recommended default:
```json
{
"mcpServers": {
"gws-admin": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/gws-admin-mcp/dist/cli.js", "serve"]
}
}
}
```
Write-enabled (use deliberately, ideally as a second entry you toggle on):
```json
{
"mcpServers": {
"gws-admin-write": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/gws-admin-mcp/dist/cli.js", "serve", "--allow-write"]
}
}
}
```
### Claude Desktop (`claude_desktop_config.json`)
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` ·
Windows: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"gws-admin": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/gws-admin-mcp/dist/cli.js", "serve"]
}
}
}
```
Restart the client after editing. You should see the `gws-admin` server with
17 tools (read-only) or 40 (write-enabled).
## Troubleshooting
| Symptom | Cause / fix |
|---------|-------------|
| `unauthorized_client` when minting a token | The domain-wide delegation grant is missing, uses the wrong client ID, or its scope list doesn't cover every scope the server requests. Re-paste the full scope string from above against the SA's OAuth2 client ID. Grants can take a few minutes to propagate. |
| `Service-account key not found at ...` | Put the JSON key at `~/.config/gws-admin-mcp/service-account.json` or set `GOOGLE_SA_KEY` to its path. |
| `DELEGATED_ADMIN ... is not set` | Add `delegatedAdmin` to `config.json` or set the `DELEGATED_ADMIN` env var. |
| `403 Not Authorized to access this resource/api` | The impersonated user is not a super-admin, or the Admin SDK API isn't enabled in the Cloud project. |
| `404` from Groups Settings calls | The *Groups Settings API* isn't enabled in the project (it's separate from the Admin SDK). |
| Write tools don't appear in the client | Working as intended — start the server with `--allow-write` or `GWS_ADMIN_ALLOW_WRITE=1`. |
| A delete/wipe call returns `Refused: ... destructive/irreversible` | Working as intended — re-issue the call with `"confirm": true`. |
| Client shows the server as failed on startup | Run `node dist/cli.js doctor` in a terminal; it prints the exact failing check. Also confirm the `args` path in your MCP config is absolute. |
## Security notes
- The service-account key impersonates a **super-admin** with org-wide power.
Treat `service-account.json` like a domain-admin password: keep it out of
git (this repo's `.gitignore` already excludes key files, `.env`, and
`config.json`), keep it `chmod 600`, and rotate it periodically.
- Prefer a dedicated Cloud project for this service account so the key is
easy to audit and revoke.
- Keep the permanent instance read-only. Enable writes in a separate instance
only when you actually intend to change things, and turn it off after.
## License & purchase
This repository is **source-available, not open source**: the code is public
so you can read and audit every line before trusting it with a super-admin
credential, but *using* it requires a license.
- **Buy a license ($34):**
[antchoutine.gumroad.com/l/gws-admin-mcp](https://antchoutine.gumroad.com/l/gws-admin-mcp)
— perpetual, includes the full write-enabled edition and updates.
- **Try it free:** the read-only edition (17 tools, no mutating code) is on
npm as [`gws-admin-mcp`](https://www.npmjs.com/package/gws-admin-mcp).
See [LICENSE](LICENSE) for the exact terms (no redistribution, no offering
it as a hosted service).