gwsadm-mcp
This server is a read-only Google Workspace security-audit MCP server that surfaces risk without mutating anything.
Run health checks – verify server version, config, and per-domain auth/API reachability.
Audit logins – detect Google-auto-disabled accounts, suspicious logins, and top login failures.
Review Gmail usage – daily send/receive volume per domain via customer usage reports.
List suspended accounts – current suspended-user snapshot per domain for IdP cross-referencing.
Look up a single user – suspension state, reason, archived status, last login, 2SV, org unit, pending password change.
List a user's OAuth grants – third-party app tokens with scopes for compromise triage.
Detect external Drive sharing – external ACL grants, link/public visibility transitions, with samples and capping.
Trace one Drive document's history – owner, ACL changes, lifecycle events; triage shared-drive findings.
Review shared-drive membership changes – who added/removed/re-roled members, including external members.
Trace message delivery – confirm whether a specific Message-ID reached given users' mailboxes and where it landed.
Summarize DMARC reports – per-domain pass/fail, reject-candidate IPs, from RUA mailbox attachments.
Check group delivery policy – posting restrictions, external-member allowance, moderation, archival state.
List group members – group metadata and member roster via Directory API.
Run a daily security brief – one-call summary across domains, plus background job variants for large tenants.
Provides read-only security auditing for Google Workspace, including account locks, suspicious logins, and external file sharing monitoring via the Admin SDK Reports API.
Click on "Deploy 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., "@gwsadm-mcprun daily security brief"
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.
gwsadm-mcp
English | 日本語
Google Workspace security-audit MCP (Model Context Protocol) server — read-only visibility into account locks, suspicious logins, and external file sharing, built on the Admin SDK Reports API (audit activities).
Named after the admin-console viewpoint (gwsadm = Google Workspace admin),
sibling of boxadm-mcp. This is
not a general-purpose Workspace MCP: it surfaces risk, it never mutates
anything.
Features
Tool | Description |
| Server version, config path, and per-domain auth probe — call at session start or after a timeout |
| Reports API |
| Reports API |
| Directory API — current snapshot of suspended accounts ( |
| Directory API |
| Directory API |
| Reports API |
| Reports API |
| Reports API |
| Gmail API — did a known Message-ID reach specific mailboxes, and where (inbox/spam/trash/archived)? For each recipient it impersonates that user via DWD and searches their own mailbox. Requires the separate |
| Gmail API — DMARC aggregate (RUA) report pass/fail summary and top reject-candidate source IPs, per domain. Impersonates the domain's configured |
| Groups Settings API — a Google Group's own posting/delivery policy ( |
| Directory API — a Google Group's basic metadata and member roster, resolved directly rather than inferred from who happened to receive one particular message. Requires the separate |
| One-call summary across all configured domains |
| Same as |
Planned: dlp_events (Reports rules; requires a Workspace edition with DLP),
token_events, admin_events.
Related MCP server: google-workspace-mcp-advanced
Auth model
Service account with domain-wide delegation (DWD) impersonating an audit-capable admin. Fully non-interactive — no browser, no token refresh rotation — so the server runs unattended (cron, MCP gateway, CI).
Grant all of the following DWD scopes on the same service-account client ID up front, in one setup pass. Adding them one at a time as each tool gets built is how a scope goes missing until the one tool that needed it starts degrading — one place, one pass, avoids the trap:
Scope | Needed by | Missing it |
|
| those tools degrade to a per-domain error |
|
| those two tools degrade to an error (per-domain for |
|
| that tool degrades to a per-domain error; everything else keeps working |
health_check needs no scope at all to respond: it is the tool to call when
a grant might be missing — it probes each domain and reports the failing
auth in a structured per-domain result instead of failing itself.
gmail_usage_report needs its own separate scope too, despite living under
the same Admin SDK Reports API as the base pass above — the "Usage report"
family (customerUsageReports) and the "Audit" activity stream
(activities().list, everything else in the base pass) are gated by two
different scopes, and having one does not imply the other:
Scope | Needed by | Missing it |
|
| that tool degrades to a per-domain error; everything else keeps working |
gmail_message_trace and dmarc_rua_summary need one more scope, granted as
a separate step — it is intentionally not bundled into the pass above:
Scope | Needed by | Missing it |
|
| those tools report a per-recipient/per-domain error; everything else keeps working |
This is a materially broader grant than the three above: it allows reading
message content for any user the service account impersonates, not just
metadata. gmail_message_trace only ever requests format="metadata" — it
never reads a message body — but dmarc_rua_summary DOES read content: it
fetches the compressed DMARC report attachment each RUA message carries
(format="full" plus attachments().get()) and parses it. Both stay within
what the grant allows either way, but only gmail_message_trace stays inside
the narrower "metadata only" habit; the narrower gmail.metadata scope was
considered and rejected for both tools because it does not support the q=
search parameter the rfc822msgid:/RUA-mailbox lookups need. Grant it on the
same service-account client ID as the other scopes (Admin console →
Security → API controls → Domain-wide delegation → find the existing client
ID → add this scope to its list), and weigh that broader exposure against how
much you actually need message-trace/DMARC reporting before turning it on for
a given domain.
group_delivery_policy and list_group_members each need their own
separate scope too — three more grants beyond the base pass, none bundled
with each other or with gmail.readonly above:
Scope | Needed by | Missing it |
|
| that tool degrades to an error; everything else keeps working |
|
| that half reports its own error; the member roster half still works independently if its own scope below is granted |
|
| same, independent of the metadata half above — the two calls never gate each other |
The Groups Settings API is a distinct product from the Directory API, hence
the separate scope; it has no readonly-only variant, but this server only
ever calls groups().get(), never a mutating method.
suspended_accounts, get_user and user_oauth_tokens all operate per
configured domain (Directory domain=/userKey=), unlike the customer-wide
Reports tools — so every domain you want covered (e.g. a separate student
domain) needs its own [domain.*] config section. Note the failure modes
differ: suspended_accounts silently omits an unconfigured domain from
its result, while get_user and user_oauth_tokens fail loudly with an
unknown-domain error (both take a domain override for an alias/secondary
address whose suffix has no section of its own).
Setup
# uv
uv pip install gwsadm-mcp
# pip
pip install gwsadm-mcpOr from source:
git clone https://github.com/shigechika/gwsadm-mcp.git
cd gwsadm-mcp
# uv
uv sync
# pip
pip install -e .Configuration
Point GWSADM_CONFIG at an INI file (default ~/.config/gwsadm-mcp/config.ini,
keep it 0600):
[gwsadm]
# optional; defaults to all [domain.*] section names
internal_domains = example.edu, mail.example.edu
[domain.example.edu]
service_account_file = /path/to/service-account.json
subject = audit-admin@example.edu
customer_id = C0xxxxxxx
dmarc_rua_mailbox = postmaster@example.edu # optional, default: postmaster@<domain>; "none" opts out
dmarc_rua_recipient = postmaster+rua@example.edu # optional, default: same as dmarc_rua_mailboxOne [domain.*] section per audited Workspace domain. internal_domains is
the allowlist used to classify sharing targets as internal vs external.
dmarc_rua_mailbox is the real user dmarc_rua_summary impersonates to read
DMARC aggregate reports — domain-wide delegation can only act as an actual user,
never as a group or alias. dmarc_rua_recipient is the address the reports are
sent to (the rua=mailto: value published in the domain's _dmarc record) and
is used only to narrow the Gmail search (to:<recipient>); it defaults to the
mailbox. Set it when the published address is a Gmail plus-subaddress such as
postmaster+rua@ (searching on it also keeps ruf= failure reports sent to
postmaster+ruf@ out of the aggregate parse) or a group that fans out to the
impersonated inbox. dmarc_rua_mailbox = none opts a domain out of DMARC reading
— e.g. when its rua= points at another domain's mailbox that a different
[domain.*] section already reads; reports are grouped by the policy domain each
report names, so they still appear under that other section.
Usage
Claude Code (plugin)
This repository doubles as a single-plugin marketplace, so Claude Code can install the server for you:
/plugin marketplace add shigechika/gwsadm-mcp
/plugin install gwsadm-mcp@gwsadm-mcpThe plugin launches uvx gwsadm-mcp and reads GWSADM_CONFIG (falls back to
~/.config/gwsadm-mcp/config.ini), the same variable described in
Configuration. /plugin install only wires up the server
process — it cannot create the config INI or the Google Cloud service-account
JSON key(s) it points at; both must already exist on the machine running the
plugin before any tool call will succeed.
uvx must be on the PATH of the process that runs Claude Code — a login
shell usually has it, but a GUI-launched app may not; install
uv system-wide if the plugin fails to start.
Claude Code (manual)
Add to .mcp.json (no env needed when the config lives at the default path;
add "env": { "GWSADM_CONFIG": "..." } only for a non-default location):
{
"mcpServers": {
"gwsadm-mcp": {
"type": "stdio",
"command": "gwsadm-mcp"
}
}
}Claude Desktop
Add the same entry to claude_desktop_config.json.
Direct Execution
gwsadm-mcpCLI Options
gwsadm-mcp --version # Print version and exit
gwsadm-mcp --check # Config + auth + API smoke for every domain, then exit
gwsadm-mcp # Start MCP server (STDIO, default)--check exit codes: 0 success, non-zero on config or auth failure.
Archiving DMARC reports (batch)
dmarc_rua_summary aggregates a rolling window for a patrol. To keep a day-by-day history, a scheduled job can dump the reports themselves:
gwsadm-mcp dmarc-reports --domain example.edu --since 2026-09-20 --until 2026-09-23 > reports.jsonReads the same RUA mailbox as
dmarc_rua_summary(samegmail.readonlyscope) for messages that arrived in[--since, --until)(UTC days, Gmailafter:/before:), every attachment and every ZIP entry (up to 20 entries and 50 MB decompressed per attachment; anything past that, or an encrypted / corrupt entry, is counted innon_report_attachments).Prints one JSON document to stdout: each report whole —
org_name,report_id,begin/end(epoch seconds of the reported period), the publishedpolicy(p,sp,pct,adkim,aspf) and its records withreasonandauth_results. Nothing is aggregated or deduplicated: some reporters split one report across several messages under the samereport_id, so deduplicate on content, not on the id.fetch_completeis true only when nothing was capped and no message, attachment or record was skipped (message_errors,non_report_attachments,dropped_records).Exit
2for a bad argument or configuration,1for an API or auth failure (e.g. the scope was revoked); nothing is written to stdout in either case.The output contains sender IPs and header domains. Keep it out of anything published.
Notes
Every result section reports
capped: truewhen a window exceeded the page budget, or when a probe's fetch errored outright (seeevent_errors) — partial coverage is never presented as "no findings". The drive scan also reportscapped_events(which eventNames were cut short). Narrowhoursor raisemax_pagesfor full coverage — on a large tenant, term-time weekdays can produce thousands ofchange_user_accessevents/day.Google's
visibility=shared_externallyis relative to the file owner's domain, so with multipleinternal_domainsa cross-internal-domain grant (e.g. student domain → staff domain) carries it too. External-ness is therefore judged againstinternal_domainsusing the grant's target:target_userfor named grants,target_domainfor domain-scoped grants (e.g. "anyone at partner.edu"; the literal domain"all"means "anyone with the link" and is judged by visibility instead).risky_visibility_eventscounts only transitions intopeople_with_link/public_on_the_web(excluding a narrowing from public down to link-only).untargeted_external_transitionsis a residual bucket for transitions intoshared_externallywith no target address or domain to classify — it is not a cross-check for grants missed elsewhere, since domain-scoped grants are already counted above.external_samples/exposure_samples/untargeted_sampleshold examples of each.Drive events are queried one audit-relevant eventName at a time, so the page budget is not consumed by view/edit noise; an event name rejected by the API degrades into
event_errorsinstead of failing the tool.change_document_visibilityandchange_document_access_scopereport the same transition as simultaneous sibling events on this API — only the latter drives classification (the former is fetched for itsacl_eventscount only), so a domain-scoped grant or a link/public exposure is never double-counted across the two. This also means the former can no longer compensate if the latter's own fetch fails: achange_document_access_scopeentry inevent_errorssetscapped: truefor that domain, and its classification counts for the window are a lower bound even thoughchange_document_visibility(and thusacl_events) may show data.A failure in one domain degrades only that domain's section (
{"error": ...}).gmail_message_tracesetsambiguous: true(withmatch_count) on a recipient whose mailbox has more than one message under the same Message-ID (mailing-list copy plus a direct CC, a quarantine-release duplicate, …) — the rest of that recipient's fields describe only the first match, not a combined answer.match_count_cappedis set alongside it when the mailbox has enough matches thatmatch_countis a lower bound rather than exact (the search does not paginate).get_userdistinguishes "this address names no account" from "the lookup failed": a plain HTTP 404 answersfound: falsewith no state fields, which is a diagnostic result — a typo'd or deleted address — and never anerror. A missing DWD scope or a transient failure answers{"error": ...}with nofoundkey instead, so the two can never be confused in either direction. Fields Google omits staynullrather than being coerced: a missingsuspendedmust not read as "the account is fine".group_delivery_policynormalizes the Groups Settings API's"true"/"false"string fields (a quirk of that API, not JSON booleans) into real booleans in its output; a field absent from Google's response staysnull, never coerced tofalse.list_group_membersruns its group-metadata and member-roster lookups independently — a tenant with only one of the two DWD scopes still gets that one section, the other reported as{"error": ...}in its place. It reportscapped: trueboth when the member roster exceeded its page budget (default 20 pages × 200/page) and when the member lookup failed outright (seemembers_error) — either way the roster is not the full one, and an emptymemberslist must never be read as a confirmed-empty group whencappedis true. Both group tools distinguish "this address is not a group" (a plain HTTP 404, verified against production for all three underlying API calls) from a real failure:group_delivery_policysetsfound: false;list_group_memberssets it too, when either both independent lookups agree with no error on either side, OR one CONFIRMS not-found while the other independently failed (that failure is then attached asgroup_lookup_error/members_lookup_errorrather than hidden) — a confirmed non-existence outweighs an unrelated error on the other scope. Only a genuine mixed state (one side not-found, the other actually finding data) falls through to the normal per-section shape instead.Read-only by design:
activities().list(Reports API),users().list/users().get/tokens().list/groups().get/members().list(Directory API),groups().get(Groups Settings API), andmessages().list/messages().get(Gmail API, metadata only) are the only API calls issued anywhere in this package.Output contains account addresses (that is the point of an audit tool): restrict access to authorized security staff.
gmail_message_tracealso returns a message snippet and headers (From/To/Cc/Subject/Date) for a matched message — treat its output with the same care as the mailbox content it is drawn from.
Development
git clone https://github.com/shigechika/gwsadm-mcp.git
cd gwsadm-mcp
# uv
uv sync --dev
uv run pytest -v
uv run ruff check .
# pip
python3 -m venv .venv
.venv/bin/pip install -e . && .venv/bin/pip install pytest ruff
.venv/bin/pytest -v
.venv/bin/ruff check .Live smoke test
The unit suite never talks to Google, which is what makes it fast — and also
what makes it blind to a tool that has stopped returning real data.
scripts/smoke_test.py runs every registered tool against the configured
tenant and fails on empty, malformed or error answers:
# uses the same config file as the server (GWSADM_CONFIG)
uv run python scripts/smoke_test.py
uv run python scripts/smoke_test.py --only oauth --tracebackRead-only. Every tool here reads an audit log or a directory snapshot; nothing in Workspace is changed.
daily_brief_startcreates a job inside the process, which expires on its own.No payloads in the report. Tool names, statuses and row counts only; server-authored error text is redacted too, since these tools deal in account addresses and document titles throughout.
Bounded. Every bounding parameter a tool offers is passed explicitly — the defaults (5 pages, 180 days, 200 events) are sized for a human asking once, and are enforced by a test that finds them from the source.
Nothing tenant-specific in the specs. The account and the document the per-user and per-document tools need are discovered at run time, and skipped when the tenant has none to offer. Two tests keep it that way: one refuses those parameters as literals, the other bans anything address-shaped anywhere in the file, because this repository is public.
An empty answer passes: no external sharing and no locked accounts is the desired state. What is asserted instead is the envelope — and, where the answer is keyed by domain, that the domain map is not empty, since a config resolving to zero domains would otherwise report every tool as working while auditing nothing.
CI enforces the cheap half: a tool registered without a probe spec fails the build (
tests/test_smoke_probes.py), so adding a tool forces the question "how would we know it works?".scripts/smoke_harness.pyis the engine and holds no Workspace knowledge: it is kept identical across the servers that share it, so fix engine bugs once and sync the file rather than patching this copy.
Releasing
Releases are automated with release-please.
Merging Conventional Commits (feat:, fix:, …)
to main keeps a release PR open with the next version and changelog. Merging
that PR tags vX.Y.Z and publishes a GitHub Release, whose release: published
event triggers the release workflow to build and publish to PyPI and the MCP
Registry. release-please owns the version in gwsadm_mcp/__init__.py and
server.json (do not bump them by hand).
The release-please workflow should be given a repository secretRELEASE_PLEASE_TOKEN (a PAT with contents: write + pull-requests: write).
The default GITHUB_TOKEN cannot create the Release that triggers the
downstream release workflow (GitHub blocks workflow runs triggered by
GITHUB_TOKEN), so without the PAT nothing gets published. The workflow falls
back to GITHUB_TOKEN when the secret is unset so PR CI keeps working on forks.
License
MIT
Available Tools
16 toolsdaily_briefA
One-call security summary across all configured domains.
Aggregates login_audit (account locks, suspicious logins) and
drive_external_sharing (external grants, new link exposure, and
untargeted_external_transitions — see that tool's docstring).
max_pages / samples are passed through to the drive scan;
max_pages defaults to the same page budget as the standalone tool,
so both report the same counters for the same window (samples
defaults lower here and only trims the example lists). Per-domain capped in the
summary means at least one underlying scan was partial — treat that
domain's counts as lower bounds (see capped_events in the drive
section for which probes were cut short).
Synchronous: on a large tenant this can exceed a client's ~60s tool-call
timeout. If it does, use daily_brief_start + daily_brief_result
(same result, run in the background) or lower max_pages.
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | ||
| samples | No | ||
| max_pages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description bears full burden. Discloses synchronous timeout risk, parameter pass-through behavior, and the 'capped' indication for partial scans. Also clarifies that samples defaults lower and only trims example lists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear paragraphs and backticks for terms. Informative but somewhat lengthy; every sentence adds value, but could be slightly more concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 3 parameters, no output schema, and no annotations, the description covers behavioral context, usage guidelines, parameter semantics, and result interpretation (capped). It is sufficiently complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so description must add meaning. Explains that max_pages/samples are passed through to drive scan, with defaults and interactions. However, the 'hours' parameter is not explicitly described beyond its schema title and default, though its purpose is clear from context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it is a 'one-call security summary across all configured domains' and specifies it aggregates login_audit and drive_external_sharing. It distinguishes from siblings like daily_brief_start and daily_brief_result by noting the alternative for timeout handling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance: use daily_brief_start + daily_brief_result or lower max_pages if synchronous call times out. Also explains defaults for max_pages and samples, and the meaning of 'capped' in results.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
daily_brief_resultA
Fetch a daily_brief_start job by id.
status is running (keep polling), done (result holds the full daily_brief
payload), error (error holds the exception type name — the message is omitted to
avoid leaking internal detail), or unknown (bad/expired id).
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. Transparently describes the four possible statuses and their implications, including security-conscious error handling (omitting message). Discloses expected polling behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Short and front-loaded with the main purpose. Uses code formatting for clarity. Every sentence adds value; no unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (1 param, no output schema), the description sufficiently covers the polling mechanism and response structure. Lacks only some detail on the 'result' payload, but acceptable for a poll-for-result tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so description must compensate. It mentions fetching 'by id' but does not elaborate on the job_id parameter's format, constraints, or source. Limited added value beyond the parameter name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it fetches a daily_brief_start job by id. Distinguishes from siblings like daily_brief_start (which creates the job) and other unrelated tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains polling logic: status values and actions (running->poll, done->parse result, error->handle error type, unknown->bad id). Provides clear context for use after starting a job, but doesn't explicitly compare with siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
daily_brief_startA
Start a daily_brief in the background; returns immediately with a job_id.
Use this instead of daily_brief when the synchronous call risks the client's ~60s
tool-call timeout (large tenants). Args mirror daily_brief. You MUST then poll
daily_brief_result(job_id) every few seconds until status is done (the full
daily_brief payload is under result) or error. On a config error returns
{"error": ...}; if too many jobs are already active returns
{"status": "rejected", ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | ||
| samples | No | ||
| max_pages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Describes immediate return, async nature, and two error states (config error, job rejection). No annotations provided, so description carries full burden. Could mention authorization needs or job lifecycle beyond polling, but adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured: front-loaded with purpose, then usage details and error states. A bit wordy but effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the necessary async flow with polling. Sibling tools provide the sync version and result fetcher. No output schema, but the polling mechanism is described. Could mention default values and parameter constraints.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has three parameters (hours, samples, max_pages) with defaults but no descriptions. Description says 'Args mirror daily_brief' but does not explain their meaning or effect. With 0% schema description coverage, this is insufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it starts a daily_brief in the background and returns a job_id. Differentiates from sibling tool daily_brief (synchronous call) by highlighting async behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use this tool (when synchronous call risks timeout for large tenants) and what to do after (poll daily_brief_result). Also covers error responses.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dmarc_rua_summaryA
Summarize DMARC aggregate (RUA) reports: pass/fail per domain, top reject-candidate IPs.
Impersonates the domain's configured dmarc_rua_mailbox (a real user --
domain-wide delegation cannot act as a group or alias; config default
postmaster@<domain>), searches it for mail addressed to
dmarc_rua_recipient (the rua=mailto: address published in DNS,
e.g. the postmaster+rua@ plus-subaddress; default: same as the
mailbox), reads the aggregate reports those messages carry, and answers "how much of this domain's mail volume is
passing DMARC, and if we moved the policy to p=reject, what would
actually get blocked?"
A record counts as PASS when either its aligned DKIM or SPF check reads
"pass" (DMARC's own OR semantics) — NOT when both do. A record counts as
a reject candidate when it is already quarantined or rejected (a tenant
already running p=quarantine/p=reject enforces this today), or when
BOTH checks fail with disposition="none" (what a stricter policy would
newly start blocking); everything else is a pass. This distinction
matters a lot in practice: a large share of legitimate mail (mailing-list
forwards, some relays) passes DMARC via SPF alignment alone with DKIM
unaligned, so counting on DKIM alone overstates the failure rate
severalfold.
reject_candidate_ips (the top top per domain by volume) is where
to actually look before flipping a policy to p=reject: a header_from
that names a SUBDOMAIN of the audited domain is governed by that
subdomain's own sp= policy, not the parent's p=, so it is not
necessarily what a p=reject change on the parent would affect.
Requires the gmail.readonly DWD scope — the same one
gmail_message_trace needs, granted PER SERVICE ACCOUNT CLIENT ID in
the Admin console (Security > API controls > Domain-wide delegation),
separately from the admin.directory.* / admin.reports.* scopes
the rest of this server uses.
Read-only: only messages().list/messages().get/
attachments().get against the one configured mailbox are issued —
see DomainClient.fetch_dmarc_rua_records.
Args:
hours: Lookback window. Default 72 (3 days): RUA reports typically
arrive roughly daily per sending source, so a single day's
window risks missing infrequent senders entirely.
domain: Configured [domain.*] section to report on. Default: all
configured domains.
mailbox: Override the configured dmarc_rua_mailbox (the user to
impersonate) for every selected domain. Set this only for an
ad-hoc check against a different inbox than the one in config;
unless recipient is also given, that inbox's own address is
searched. Also re-enables a domain configured with
dmarc_rua_mailbox = none for the duration of the call.
Validated as an email-shaped address (rejected otherwise).
recipient: Override the address searched for (to:) for every
selected domain -- the rua=mailto: value in DNS when it is
not the mailbox itself. Validated as an email-shaped address
(rejected otherwise) before use, since it is interpolated into
a Gmail search query.
max_pages: Gmail messages().list pages (100 messages each) to
walk per domain. capped=true in the result means more pages
existed — a capped fetch UNDER-counts real report volume, not
just a lower bound on some other total, since every matching
message must be walked (there is no server-side aggregate to
fall back on).
top: How many reject-candidate source IPs to return per domain
(highest volume first). The per-domain pass/quarantined/
rejected/undisposed_fail totals themselves are never truncated.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| hours | No | ||
| domain | No | ||
| mailbox | No | ||
| max_pages | No | ||
| recipient | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full burden and handles it impressively. It discloses impersonation behavior, the exact read-only Gmail API calls used, the count semantics for PASS vs reject candidates, the subdomain sp= caveat, and the fact that capped fetches under-count real volume. This is far more behavioral detail than annotations alone would typically provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but densely packed with information that earns its place: semantics, real-world caveats, scope prerequisites, and parameter explanations are all relevant. It is front-loaded with the main summary and then structures the rest with clear 'Args' entries, making the length navigable rather than bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, absence of annotations, and absence of an output schema, the description is remarkably complete. It explains the data source, the pass/fail decision rule, the reject-candidate definition, the subdomain edge case, the permissions requirement, and the meaning of truncated results. An agent has enough information to invoke it safely and interpret the outcome correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for every parameter. It does: hours, domain, mailbox, recipient, max_pages, and top each receive meaningful context beyond their raw schema types, including defaults, validation behavior, and result-affecting caveats. This fully compensates for the empty schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-plus-resource statement: 'Summarize DMARC aggregate (RUA) reports: pass/fail per domain, top reject-candidate IPs.' This clearly identifies both the action and the subject, and the detail about policy-rejection impact further distinguishes it from sibling tools like gmail_message_trace.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when the tool is appropriate—auditing DMARC pass/fail and estimating the effect of moving to p=reject—and even compares the required scope to that of gmail_message_trace. It does not explicitly list alternative tools to use instead, but the intended use case is unambiguous and well-bounded.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
drive_doc_activityA
Full audit history of one Drive document: owner, ACL changes, lifecycle.
The triage companion to drive_external_sharing: a sharing finding names
a doc_id, and judging it requires who OWNS the document (an individual
user vs. a shared drive completely changes the risk read) and its grant
history over time. Uses a server-side doc_id filter, so the page budget
is spent on this one document only.
owner / doc_title are taken from the document's own events (a
shared-drive-owned file reports the drive's name — not a user address — as
owner). events lists ACL and lifecycle events newest-first
(view/edit/download noise is counted in event_counts but not listed);
events_truncated is set when more matched than max_events.
The doc_id filter matches at the ACTIVITY level and one activity can
carry sibling events for OTHER documents (a multi-file share is one
activity with one event per file) — events whose own doc_id parameter
does not match (or is absent) are excluded from every output field and
tallied in sibling_events_skipped instead, so a bulk action cannot
contaminate this document's history or misattribute its owner.
An empty result means no events in the window for the queried tenant —
NOT proof the document does not exist (history older than the Reports API
retention, or a document living in a different tenant, looks the same).
Args:
doc_id: Drive document id (from a sharing finding's doc_id field).
days: How far back to scan (Reports API retains roughly 6 months).
domain: Restrict to one configured domain/tenant (default: all).
max_pages: Reports page cap per domain; capped=true means more existed.
max_events: Cap on listed events (counts are unaffected).
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | ||
| doc_id | Yes | ||
| domain | No | ||
| max_pages | No | ||
| max_events | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description fully explains behavioral traits: it uses a server-side filter, explains how page budget is spent, details events listing vs counts, the meaning of 'events_truncated', and how sibling events from bulk actions are excluded. It also covers limitations like retention and multi-tenant scenarios.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections and bullet points, but it is somewhat lengthy. However, every sentence adds value and the key information is front-loaded. It could be slightly more concise, but overall it is effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (5 parameters, no annotations or output schema), the description covers essential aspects like return fields (owner, doc_title, events, etc.), edge cases (empty results, sibling events), and parameter effects. However, a dedicated output schema or more explicit return value documentation would improve completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description's 'Args' section provides thorough explanations for all five parameters: 'doc_id', 'days', 'domain', 'max_pages', and 'max_events'. It explains their purpose and default behavior, adding significant meaning beyond the schema's titles and default values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool provides 'full audit history of one Drive document' including owner, ACL changes, and lifecycle. It also explicitly distinguishes itself as the companion to 'drive_external_sharing', making its purpose and uniqueness evident.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance: use this when you have a 'doc_id' from a sharing finding to determine ownership and history. It contrasts with 'drive_external_sharing' and explains when not to use it (e.g., for sharing findings that haven't been triaged). It also clarifies that an empty result does not prove the document doesn't exist.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
drive_external_sharingA
Report Drive ACL grants to external targets and new link/public exposure.
Counts grants whose target (target_user address, or target_domain
for domain-scoped grants) is outside the configured internal domains
(revocations are reported separately, not as exposure) and visibility
transitions into link/public access (people_with_link /
public_on_the_web, excluding a narrowing from public down to
link-only; Google's shared_externally is owner-domain relative, so
external-ness is judged by the target instead).
untargeted_external_transitions counts transitions into
shared_externally with no target address or domain (e.g. scope
became "anyone with the link" — target_domain: "all" — or an
unresolved target); it is a residual bucket, not a cross-check for
missed named grants, since domain-scoped grants are already classified
above. external_samples / exposure_samples / untargeted_samples
hold examples of each. A self-grant of owner on change_user_access
/change_acl_editors (a user creating their own new file — every
Form/Sheet/Doc submission does this) is excluded from
risky_visibility_events: it always reports a visibility transition
from a missing prior state, which is indistinguishable from a genuine
narrow-to-wide exposure event by visibility fields alone, but is not
exposure of anything pre-existing. When no target_user is named
(the change_acl_editors shape), a missing target alone is not proof
of creation — an admin bulk-transferring ownership of a pre-existing,
already-shared file (e.g. offboarding) looks the same — so this case is
corroborated against the event's own owner parameter (self-action
only if owner matches the actor); if owner itself is absent the
conservative default is to count it rather than risk dropping a real
ownership change. This exclusion is deliberately never applied to
change_document_access_scope/change_document_visibility
(see SELF_CREATION_GRANT_EVENTS) — those carry no target_user and
can legitimately report new_value: "owner" for a real transition, so
excluding them there would blind this tool's primary signal instead of
just removing creation noise. Each audit-relevant event name is
queried separately so the page budget is not consumed by view/edit noise
(change_document_visibility is fetched for its acl_events count
only — it duplicates change_document_access_scope on this API and
does not drive classification, so it cannot compensate if that probe's
own fetch fails). capped_events lists event names that exceeded
max_pages*1000 events; capped is also set when any probe's fetch
errored outright (see event_errors) — either way, treat that
domain's counts as lower bounds. Narrow hours or raise max_pages
for full coverage (term-time weekdays see >10k change_user_access
events/day).
Shared-drive caveat: a file created INSIDE a shared drive emits
change_user_access events for each existing drive member (ACL
propagation), so an external member merely uploading files looks like
bulk external sharing here. When a finding's documents share one owner
that is a drive NAME rather than a user address, triage with
drive_doc_activity (per-document history: the "grants" coincide with
create/upload by the same actor) and
shared_drive_membership_changes (who added the members, and when).
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | ||
| domain | No | ||
| samples | No | ||
| max_pages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It meticulously discloses behavioral traits: exclusions (self-grants, shared drive propagation), limitations (capped events, event errors), and handling of ambiguous cases (missing target_user).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very long but packed with necessary details. While each sentence adds value, the length could be trimmed by grouping related caveats. However, the structured flow (starting with core purpose, then details, then caveats) is logical.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (4 parameters, no output schema, many edge cases), the description is remarkably complete. It covers caveats, error conditions, relationships to sibling tools, and provides actionable advice for triage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description implicitly adds meaning to parameters: 'hours', 'domain', 'samples', and 'max_pages' are discussed in context (e.g., 'Narrow hours or raise max_pages'). However, it does not explicitly map each parameter to its purpose, slightly reducing clarity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it reports Drive ACL grants to external targets and new link/public exposure, with a specific verb and resource. It also distinguishes from sibling tools like drive_doc_activity and shared_drive_membership_changes by mentioning them in the shared-drive caveat.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance: when to narrow hours or raise max_pages, and when to use alternative tools (drive_doc_activity, shared_drive_membership_changes). It also explains when not to trust counts (capped events) and how to interpret results.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_userA
Look up ONE named account's current state — the "why can't this person sign in" tool.
Answers a helpdesk ticket that already names the exact address: is the account suspended (and for what reason, since when), archived, enrolled in or enforced into 2-step verification, when did it last log in, which org unit is it in, is a password change pending. One Directory API request, no pagination.
Use this — not suspended_accounts — whenever the address is known.
That tool lists only accounts that ARE suspended, so it can never confirm
that a given address is not suspended, and once that list exceeds its
page cap absence stops being evidence either way — after spending far more
API calls than this. suspended_accounts is for the domain-wide sweep it
is actually named for.
This directory is downstream of the identity provider, not the master. Read
the answer as "what Google Workspace currently believes about this account"
and compare it against the IdP's own record, which is authoritative for who
the account is. A disagreement is usually drift on this side rather than a
mistyped address — an account the IdP still authenticates can be suspended
or archived here, and an address the IdP does not assert at all will simply
come back found: false.
An address that names no account returns found: false with no state
fields. That is a normal, expected answer — a typo'd or long-deleted
address — and is itself the diagnostic result, NOT a failure. A missing
DWD scope, a rejected credential or a transient API failure is reported as
{"error": ...} instead. The two are deliberately distinct: never read
found: false as "the lookup did not work", and never read an error
as evidence about whether the account exists.
Read-only (Directory API users().get; no mutating method exists in
this package). Requires the admin.directory.user.readonly DWD scope —
the same one suspended_accounts uses, so a tenant already running that
tool needs no additional grant.
Args:
username: Exact user email, passed through as the Directory API
userKey (primary or alias address both work on Google's side;
the returned email is the account's canonical primary one).
domain: Configured [domain.*] section to route the lookup through.
Default: resolved from the username's suffix. Set it explicitly
when the address uses an alias/secondary domain that has no
config section of its own (common when copying addresses from
mail headers or IdP logs).
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| username | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description transparently explains behavior: it returns 'found: false' for nonexistent accounts, distinguishes that from errors, notes the directory is 'downstream of the identity provider' (data may be stale), and states it is read-only with the required scope. This goes beyond any annotations (none provided) and gives a thorough understanding of side effects and edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely verbose and repeats the exact same content in three separate paragraphs (e.g., the 'found: false' and 'read-only' points appear three times). A single concise paragraph would suffice, making the current structure wasteful and harder to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite the verbosity, the description is complete: it covers purpose, usage, behavioral nuances (stale data), error handling, scope requirements, and alternatives. It does not need an output schema since none is provided, but it gives sufficient context for an agent to decide when and how to use the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description thoroughly explains both parameters, despite 0% schema coverage. For 'username', it clarifies that aliases work and the returned email is canonical; for 'domain', it explains the default behavior and when to set it explicitly. This adds significant meaning beyond the raw schema definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose as 'Look up ONE named account's current state' and explicitly differentiates it from the sibling tool 'suspended_accounts' by stating 'Use this — not ``suspended_accounts`` — whenever the address is known.' This provides a specific verb and resource, and distinguishes it from alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage conditions: 'Answers a helpdesk ticket that already names the exact address' and contrasts with the sibling tool: 'That tool lists only accounts that are suspended...' It also explains when not to use it, providing clear guidance on when to choose this tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_message_traceA
Check whether a message (by RFC 822 Message-ID) reached specific users' mailboxes.
Answers "who got this email and who didn't" for a KNOWN Message-ID and a KNOWN candidate recipient list — there is no Workspace API to search across every user for one message, so the caller supplies who to check (a mailing-list roster, or simply the people who reported a problem). For each recipient this impersonates that exact user via domain-wide delegation and searches their own mailbox (including Spam and Trash) for the Message-ID.
Requires the gmail.readonly DWD scope — granted PER SERVICE ACCOUNT
CLIENT ID in the Admin console (Security > API controls > Domain-wide
delegation), separately from the admin.directory.* / admin.reports.*
scopes the rest of this server uses, and NOT on by default. A domain
missing that grant reports a per-recipient error rather than a
silent "not found" — the two must never be confused, since "not found"
here can also legitimately mean the message was delivered and later
deleted by the user, or never delivered at all; this tool cannot tell
those apart, only "a match currently exists in this mailbox" from "it
doesn't".
Read-only: only messages().list and messages().get (metadata
only, never the message body) are issued against each impersonated
mailbox — see DomainClient.find_message_by_id.
A per-recipient result sets ambiguous: true (with match_count)
when more than one message in that mailbox shares the Message-ID (e.g. a
mailing-list copy plus a direct CC) — the other fields describe only the
first match in that case, not a combined answer. match_count_capped
is set alongside it when the mailbox has enough matches that
match_count itself is a lower bound, not exact.
Args:
message_id: The RFC 822 Message-ID to search for, with or without
angle brackets. Must be shaped like an address (local@domain,
no whitespace) — this is validated before use, since it is
interpolated into a Gmail search query.
recipients: Comma- and/or whitespace-separated exact recipient email
addresses to check (max 50 per call — split a larger list across
multiple calls rather than expecting a partial result).
domain: Configured [domain.*] section to route EVERY recipient
through. Default: resolved per-recipient from their own address
suffix, so one call can cover a mixed staff/student list. Set
this only when recipients use an alias/secondary domain with no
config section of its own.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| message_id | Yes | ||
| recipients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the behavioral transparency burden. It discloses impersonation via domain-wide delegation, searches including Spam and Trash, the read-only use of messages().list and messages().get (metadata only), the per-recipient error vs. "not found" distinction, the inability to distinguish deleted vs. never delivered, and the ambiguous/match_count cap behavior. This is exemplary disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Though long, the description is structured into a clear one-line purpose, a rationale paragraph, scope/permission warnings, behavioral caveats, and an Args list. Every sentence adds necessary information for a complex tool, and the front-loaded first sentence immediately answers what the tool does.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the sparse schema, absence of annotations, and no output schema, the description provides comprehensive context: return semantics, error handling, ambiguity flags, domain configuration, scope prerequisites, and read-only behavior. It is sufficiently complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does. The Args section explains message_id angle-bracket flexibility and address-shape validation, recipients format and max count, and the domain parameter's default per-recipient resolution and special alias-domain use case. This adds substantial meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb + resource + scope: "Check whether a message (by RFC 822 Message-ID) reached specific users' mailboxes." It clearly defines the tool as a targeted per-recipient lookup, distinct from the other sibling tools which focus on health, audits, or drive activity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: for a KNOWN Message-ID and a KNOWN candidate recipient list, and explains the absence of a cross-user Workspace API. It gives concrete operational guidance such as the 50-recipient limit, splitting larger lists, domain routing, and the required gmail.readonly DWD scope, making usage conditions unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gmail_usage_reportA
Daily Gmail send/receive counts per domain (Admin SDK customerUsageReports).
Answers "how much Gmail traffic did this domain send/receive on day X" --
a customer-level daily counter, NOT a per-user or per-message breakdown
(the Reports API has no such thing; login_audit's activity stream is
the per-event alternative for that, at the cost of no volume total).
Each day's fetch is independent: a domain missing the DWD scope reports
one whole-domain error (there is no point retrying days times for
an identical scope failure), but a single date's fetch failing for some
other reason (Google's processing for that day not finished yet is a
known lag on this API family; a transient error) only skips that one
date, recorded in date_errors -- the rest of the window still comes
back. The per-domain result also carries capped -- true if ANY
date's fetch hit the (rare, since a single day's customer report is
normally one record) pagination limit -- so a truncated day's counters
are never mistaken for the complete picture.
Requires the admin.reports.usage.readonly DWD scope, granted PER
SERVICE ACCOUNT CLIENT ID in the Admin console (Security > API controls >
Domain-wide delegation) -- a DIFFERENT scope from
admin.reports.audit.readonly (the one login_audit,
drive_external_sharing, drive_doc_activity,
shared_drive_membership_changes and daily_brief use), even though
both live under the same Admin SDK Reports API. Having one does not
imply the other; grant this one separately.
Read-only: only customerUsageReports().get() is issued, restricted to
the two Gmail counters this tool reports via the API's own parameters
filter (:data:GMAIL_USAGE_PARAMETERS) rather than pulling every
application's counters.
Args:
days: How many days back to report, ending YESTERDAY (not today --
the current day's data is not final until it ends) in the
Reports API's own UTC-8:00/Pacific-Standard-Time date anchor.
Must be 1..:data:MAX_USAGE_REPORT_DAYS -- 0/negative
would otherwise silently return a well-formed, error-free empty
result indistinguishable from "queried correctly, zero Gmail
traffic that window", and an unbounded value drives an unbounded
(domain x date) fan-out (one blocking API call per task, even
though they run concurrently).
domain: Configured [domain.*] section to report on. Default: all
configured domains.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | ||
| domain | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and meets it thoroughly: discloses read-only nature (only customerUsageReports().get() issued), the per-domain error vs date_errors partial-failure model, the capped pagination flag, the separate DWD scope requirement distinct from the audit scope, and the UTC-8 date anchor. Exceptionally rich behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and scope before behavioral detail, with a clearly marked Args section. The description is long but every sentence carries operational value given the tool's complexity (auth, failure modes, pagination). Slight deduction for density, but no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 2 params, no output schema, no annotations, and 0% schema coverage, the description is essentially complete: it covers return behavior (error vs date_errors), the capped truncation signal, auth prerequisites, and full parameter semantics. An agent could call this correctly with zero additional research.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate and does so fully. For days it explains the 'ending YESTERDAY' semantics, the range constraint, and the silent-failure trap of 0/negative values producing an indistinguishable empty result. For domain it explains the configured [domain.*] section concept and the default. No meaning is left to schema inference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Daily Gmail send/receive counts per domain (Admin SDK customerUsageReports)'. Immediately states what it is NOT (per-user or per-message breakdown) and names login_audit as the per-event alternative, clearly distinguishing it from the 15 siblings without requiring schema inspection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names login_audit as the alternative for per-event breakdown and explains the tradeoff (no volume total). States when this tool fits ('how much Gmail traffic did this domain send/receive on day X') and the scope precondition. Also explains the non-retry behavior on scope failure, giving the agent a clear decision rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
group_delivery_policyA
Check a Google Group's own posting/delivery policy — why an external sender's mail never arrived.
A Group's access-control layer sits IN FRONT of Gmail delivery: when
who_can_post is restricted (e.g. domain-members-only), an external
sender's message is rejected there and never generates a per-recipient
Gmail delivery event at all — gmail_message_trace (a real mailbox) and
any Reports-API-based delivery trace both see nothing for that address,
indistinguishable from a genuine delivery failure without this. Use this
FIRST when a group address "isn't receiving" mail from an external
sender, before chasing it as a transport/spam problem.
Read-only: only groups().get() is issued (Groups Settings API).
Requires the apps.groups.settings DWD scope — granted PER SERVICE
ACCOUNT CLIENT ID in the Admin console (Security > API controls >
Domain-wide delegation), separately from every other scope this server
uses, and NOT on by default.
Returns who_can_post (e.g. ALL_IN_DOMAIN_CAN_POST blocks external
senders entirely; ANYONE_CAN_POST allows them), allow_external_members,
is_archived, message_moderation_level, spam_moderation_level,
allow_web_posting. Sets found: false (no policy fields) when
group_email does not name any group in this domain — that is a
normal, expected answer for a bad/typo'd address, not an error.
Args:
group_email: The group's address (e.g. "team.gen@example.edu").
domain: Configured [domain.*] section to route the lookup through.
Default: resolved from the address's suffix.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| group_email | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and excels. It discloses read-only behavior ('only groups().get() is issued'), the required scope and its non-default delegation, and the important nuance that found:false is a normal result for a nonexistent group, not an error. This goes well beyond a simple 'checks policy' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear paragraphs: purpose, underlying behavior, read-only/scope, return fields, and args. Every sentence adds value, and the length is justified by the technical complexity and the need to prevent misdiagnosis. It is front-loaded with the most important purpose statement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of an output schema, the description thoroughly explains return fields (who_can_post, allow_external_members, etc.), the found:false edge case, the required scope, and when to use the tool. It is complete enough for an agent to understand the tool's behavior, prerequisites, and expected outputs without additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain both parameters. It does: group_email is given an example and described as the group's address, while domain is explained as a routing section with a default resolved from the address suffix. This adds meaningful semantics beyond the bare schema types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Check a Google Group's own posting/delivery policy — why an external sender's mail never arrived,' a specific verb+resource that immediately clarifies the tool's purpose. It distinguishes itself from siblings like gmail_message_trace by explaining that it checks the group-level policy before Gmail delivery, unlike mailbox-level traces.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is provided: 'Use this FIRST when a group address "isn't receiving" mail from an external sender, before chasing it as a transport/spam problem.' It also contrasts with gmail_message_trace and Reports-API traces, explaining why this tool is the right first step and excluding alternatives in the same context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_checkA
Report service status, version, and per-domain auth/API reachability.
Always returns the same keys: status (healthy / degraded / error), service, version, config, and domains (per-domain auth result). Lightweight: one 1-item login query per domain.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses that the tool is lightweight (one query per domain) and always returns the same keys, implying idempotency. It does not explicitly state it is read-only, but the verb 'report' strongly suggests no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise—two sentences, no wasted words. It front-loads the purpose and then adds key details (return keys, performance). Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters and no output schema, the description fully covers what an agent needs: what the tool does, what it returns, and that it is lightweight. No gaps remain for effective invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, and schema coverage is 100%. The description adds value by detailing the output keys and performance characteristics, going beyond what the empty schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool reports 'service status, version, and per-domain auth/API reachability', using a specific verb-report and resource-health check. It distinctly differs from sibling tools like daily_brief or login_audit, which address other aspects.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies use for checking system health, and the sibling context makes the purpose unambiguous. However, it lacks explicit guidance on when not to use it or alternatives, though none are obviously needed given its unique function.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_group_membersA
List a Google Group's basic metadata and member roster (Directory API).
Resolves a group's actual membership directly, independent of any
specific message ever having been sent to it — unlike inferring
membership from Reports API delivery-event fanout (applicationName=gmail),
which only shows members who received one PARTICULAR message and
requires one to already exist to trace. Pair with gmail_message_trace
to deep-dive a specific member's mailbox once the roster is known, or
with group_delivery_policy to see why the group as a whole may not be
receiving mail at all.
Read-only: only groups().get() and members().list() are issued
(Directory API), never a mutating call. Requires the
admin.directory.group.readonly and
admin.directory.group.member.readonly DWD scopes — granted PER
SERVICE ACCOUNT CLIENT ID in the Admin console, separately from every
other scope this server uses, and NOT on by default. The two calls are
independent: a tenant with only one of the two scopes granted still gets
that one section, with the other reported as {"error": ...} in its
place rather than failing the whole call — only when BOTH fail does the
tool return a single top-level error.
Sets found: false (no group/members sections) when
group_email does not name any group in this domain — a normal,
expected answer for a bad/typo'd address, not an error. This
triggers both when BOTH calls agree with no error on either side, AND
when one call CONFIRMS not-found while the other independently failed
(its own error is then attached as group_lookup_error /
members_lookup_error) — a confirmed non-existence from one
independently-scoped call is stronger evidence than an unrelated
failure on the other, and must not be buried under it.
Args:
group_email: The group's address.
domain: Configured [domain.*] section to route the lookup through.
Default: resolved from the address's suffix.
max_pages: Pagination cap for the member roster (Directory API hard
limit 200 members per page). Default 20 (≤4,000 members) —
raise for an unusually large group. capped: true means the
roster is NOT the complete one — either more pages existed
beyond this, or the member lookup failed outright (see
members_error); either way it must never be read as the
full membership, and an empty members list must not be
mistaken for a confirmed-empty group when capped is true.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| max_pages | No | ||
| group_email | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description fully carries the transparency burden. It discloses read-only behavior, the two Directory API calls issued, required scopes (including per-service-account grant), partial success semantics when one scope is missing, and the meaning of found:false and capped:true, including nuanced edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence contributes valuable information. It is structured into clear sections: purpose, comparison with alternatives, read-only/scopes, found/capped semantics, and arguments. The first sentence fronts the primary purpose, and the level of detail is justified by the tool's behavioral complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (3 parameters, no output schema, complex edge cases), the description is exceptionally complete. It covers return behavior, error handling, scope requirements, and interpretation of edge conditions like found:false and capped:true, ensuring the agent can invoke and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 0% schema description coverage, the description explains every parameter in detail: group_email as the group's address, domain with default resolution from address suffix, and max_pages with its pagination cap, default, and the meaning of capped:true. This far exceeds the schema's minimal definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'List a Google Group's basic metadata and member roster (Directory API).' It clearly distinguishes from sibling tools like gmail_message_trace and group_delivery_policy by explaining the unique value of resolving actual membership directly, independent of any message having been sent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance: it explains when to pair with gmail_message_trace for deep-diving a member's mailbox and with group_delivery_policy for group-level delivery issues. It also contrasts with the alternative of inferring membership from Reports API delivery-event fanout, clarifying when this tool is preferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
login_auditA
Audit the login log: Google-auto-disabled accounts, suspicious logins, failure top-N.
Answers "did Google itself decide something was wrong with an account here,
and with which account?" — the question a "my mail suddenly stopped working"
ticket usually turns out to be. account_disabled_* is Google reporting
that it locked an account (leaked password, hijacking, spamming);
suspicious_login and gov_attack_warning are warnings without a lock.
In both sections user is the account the event is ABOUT, not an actor
who did something: Google raised these itself, so the actor is Google and
the account is read from the event's affected_email_address. Treat a
hit as evidence about that account, and reach for get_user next for its
current state.
An account_disabled_spamming entry means Google observed outbound spam,
which is a compromise finding, not a delivery problem — the account was
almost certainly being used by someone else. The IdP upstream is a separate
system and is NOT disabled by this: an account locked here can still
authenticate there until it is disabled there too.
Combine with a Directory suspended-users snapshot (Phase 2) for current
state. Each section carries capped (window not fully scanned) — treat
counts as lower bounds then.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| hours | No | ||
| domain | No | ||
| include_failures | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and does an excellent job disclosing semantics: it explains what account_disabled_spamming means, that some events are warnings, and that results may be capped. It is very transparent about behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy and somewhat repetitive (e.g., the account_disabled_spamming explanation appears twice). It is not overly verbose but could be tightened without losing essential context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description gives rich context about the tool's purpose, interpretation of results, and how to combine with other tools. However, it does not explain the parameters or provide an output schema, leaving some aspects undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description provides zero information about the parameters (top, hours, domain, include_failures). Since schema descriptions are absent (0% coverage), the description fails to compensate for the missing parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool audits login events and specifically answers the question about Google-disabled accounts, distinguishing it from sibling tools like suspended_accounts or gmail_message_trace.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides context on when to use (audit logins, interpret disabled accounts) and even suggests combining with a Directory snapshot, but it does not explicitly contrast with alternative tools or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
suspended_accountsA
Snapshot of currently suspended Google Workspace accounts, per domain.
A suspended-but-still-provisioned account is a common attack surface: an account disabled in Google may remain enabled in a downstream IdP (e.g. KeyCloak), where a password-spray attacker can still authenticate through it. Cross-reference this list against the IdP to find and disable such gaps.
Unlike login_audit (which reports the event of Google disabling an
account within a time window), this is current state — every account
suspended right now, regardless of when. Read-only (Directory API
users().list with query=isSuspended=true). Requires the
admin.directory.user.readonly DWD scope; a domain missing that grant
degrades to {"error": ...} for that domain only. capped is set when
max_pages was hit before the listing was exhausted.
Coverage is per configured domain (Directory domain= filter), unlike the
customer-wide Reports tools — every domain you want covered (e.g. a separate
student domain) must have its own [domain.*] config section, or its
suspended accounts are not listed.
Args:
domain: Restrict to one configured domain (default: all).
max_pages: Page cap (500 accounts/page); capped=true means more exist.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| max_pages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Fully discloses behavior: read-only, Directory API call, query parameter, required scope, error behavior for missing grants, pagination with 'capped' flag, and domain-specific coverage. No annotations, so description carries full burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with main purpose, then adds details. Each sentence adds value, but slightly verbose. Good structure with examples and clarifications.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers key behavioral aspects, but lacks output schema details (e.g., fields in the returned account list). Mentions 'capped' flag but not the response format. Still complete enough for most use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Adds meaning beyond schema: domain is optional and restricts scope; max_pages controls page count and 'capped' indicates more results. Schema coverage is 0%, so description compensates well, though could be more structured per parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns a 'Snapshot of currently suspended Google Workspace accounts, per domain.' It uses specific verbs and resources, and distinguishes itself from the sibling 'login_audit' by contrasting event vs. state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance on when to use (cross-reference against IdP for security gaps) and when not (vs. login_audit for events). Also states prerequisites like DWD scope and domain configuration.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
user_oauth_tokensA
List third-party OAuth apps one user has granted account access to.
Account-compromise triage tool for the case login_audit and
suspended_accounts are both blind to: a malicious app used a
previously-granted OAuth token to read/delete mail or Drive files without
ever generating a fresh login event. Check each entry's scopes for
Gmail/Drive access on an unrecognized client_id/display_text —
Google's own apps (e.g. iOS/Android account sync) show up too and are
normal noise.
Read-only (Directory API tokens().list; never tokens().delete()).
Requires the admin.directory.user.security DWD scope — distinct from
admin.directory.user.readonly used by suspended_accounts; a domain
missing that grant returns {"error": ...}. No pagination: the API
returns a user's full grant list in one response.
Args:
username: Exact user email, passed through as the Directory API
userKey (primary or alias address both work on Google's side).
domain: Configured [domain.*] section to route the lookup through.
Default: resolved from the username's suffix. Set it explicitly
when the address uses an alias/secondary domain that has no
config section of its own (common when copying addresses from
mail headers or IdP logs).
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | ||
| username | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite no annotations, the description fully discloses read-only nature (Directory API tokens().list, never delete), required scope admin.directory.user.security, error on missing scope, and no pagination (full list in one response).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured: concise lead sentence, then scenario context, technical details, and parameter docs. Every sentence adds value; no redundancy. Length is appropriate for the complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers most aspects: purpose, usage, behavior, parameters. Lacks explicit description of return format (e.g., list of objects with fields like scopes, client_id, display_text). However, the guidance on what to check partially compensates. No output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage, the description adds essential meaning: username as exact email passed as userKey (primary/alias work), domain for routing with default resolution and explicit use for alias/secondary domains. This far exceeds schema-only info.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists OAuth tokens granted by a user, differentiating itself from sibling tools like login_audit and suspended_accounts by addressing a specific blind spot: malicious OAuth apps using previously-granted tokens without generating new login events.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit context: use for account-compromise triage when login_audit and suspended_accounts are insufficient. Guides the agent to check scopes for Gmail/Drive access and to ignore Google-owned noise. Also explains domain routing and when to set domain explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.17.0- Added
dmarc_rua_summary - Added
gmail_usage_report
1 tool update
v0.14.0- Added
get_user
2 tool updates
v0.12.0- Added
group_delivery_policy - Added
list_group_members
1 tool update
v0.10.0- Added
gmail_message_trace
2 tool updates
v0.9.2- Added
drive_doc_activity - Added
shared_drive_membership_changes
8 tool updates
v0.1.0- First observed
daily_brief - First observed
daily_brief_result - First observed
daily_brief_start - First observed
drive_external_sharing - First observed
health_check - First observed
login_audit - First observed
suspended_accounts - First observed
user_oauth_tokens
TDQS
Scored across 16 tools
Tools have distinct purposes: account state (get_user), sharing (drive_external_sharing), delivery (gmail_message_trace), group policy (group_delivery_policy), etc. However, login_audit and daily_brief overlap in surfacing security events, and suspended_accounts vs login_audit's account_disabled_* could be confused without careful reading.
Tool names are mostly descriptive noun phrases (get_user, login_audit, suspended_accounts) but lack a consistent verb_noun pattern. Some use get_ prefix (get_user, gmail_message_trace has get implied but not consistent), while others are plain nouns. daily_brief_start/result are clear but break the pattern.
With 16 tools for a comprehensive Google Workspace admin MCP server, the count is on the higher end but reasonable for the domain coverage (user, drive, groups, mail, reports). Each tool addresses a distinct function, though some could be combined (e.g., daily_brief_start/result could be one async tool).
The server covers account management, security audits, mailbox tracing, group management, and Drive sharing analysis. Minor gaps: no tool to directly manage (create/update/delete) users or groups, and no tool for checking group membership changes over time (only current state). But the focus is security auditing, which is well covered.
Maintenance
Related MCP Connectors
Paid remote MCP for AI Studio Workspace approval gate MCP, structured receipts, audit logs, and revi
A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for Google Workspace APIs - Docs, Sheets, Drive, Gmail, and Calendar. Enables reading, creating, and editing Google Docs and Sheets, managing comments, reading emails, and viewing calendar events.3424 npm17MIT
- AlicenseBqualityDmaintenanceProduction-ready MCP server for Google Workspace providing broad coverage across Gmail, Drive, Calendar, Docs, Sheets, and more, with safe-by-default write operations and markdown-to-Google-Docs support.100MIT
- FlicenseBqualityDmaintenanceMCP server providing full access to Google Workspace services (Gmail, Drive, Calendar, Docs, Sheets, Slides, Forms, Tasks, Contacts) using OAuth authentication.1001-
- FlicenseNot gradedqualityCmaintenanceRead-only MCP server for Microsoft Entra ID (Azure AD) that enables querying user sign-in logs, group memberships, and assigned Microsoft 365 licenses via Microsoft Graph API. Provides security and audit visibility without any write operations.-