Skip to main content
Glama
flt-sudo

gmail-mcp-server

by flt-sudo

gmail-mcp-server

CI

MCP server that manages multiple Gmail accounts under one Google OAuth client, with per-call account routing and cross-account search.

  • 12 tools, all prefixed gmail_: account management (add / list / remove), read (search / thread / message / labels), write (send / reply / draft / labels / trash)

  • Every inbox tool takes an optional account (email or alias); gmail_search_threads also accepts account: "all" to fan out across every stored account and merge results by date

  • Per-account access levels chosen at add time: readonly, modify (the default), or send. Tools that need more access than an account has refuse with a clear message instead of a raw Google 403

  • Tokens live in ~/.config/gmail-mcp/accounts.json (file 0600 in a 0700 directory, refresh tokens only — no access tokens are persisted)

  • Runs over stdio for a local client, or over Streamable HTTP with bearer-token auth for a hosted setup

  • Unit tests, protocol checks on both transports, and a secret scan run in CI on every push

Requirements

  • Node.js ≥ 18

  • A Google Cloud OAuth client (Desktop app) — see below

Related MCP server: gmail-mcp

Google Cloud setup (one-time)

  1. Go to Google Cloud Console and create (or pick) a project.

  2. Enable the Gmail API: APIs & Services → Library → search "Gmail API" → Enable.

  3. Configure the OAuth consent screen (APIs & Services → OAuth consent screen):

    • User type: External is fine for personal accounts.

    • Fill in the required app name / support email fields.

    • Publishing status: set to "In production." This matters: in Testing mode, Google expires refresh tokens after 7 days, so you would have to re-authenticate every account weekly. In production status, tokens persist.

    • You do not need Google's app verification for personal use. During consent you'll see an "unverified app" warning — click Advanced → Go to (app name). This is expected and acceptable for a private tool.

  4. Create the OAuth client: APIs & Services → Credentials → Create Credentials → OAuth client ID → Application type: Desktop app.

  5. Copy the client ID and client secret and provide them to the server one of two ways:

    Option A — environment variables (e.g. in your MCP client config):

    GMAIL_MCP_CLIENT_ID=xxxxx.apps.googleusercontent.com
    GMAIL_MCP_CLIENT_SECRET=GOCSPX-xxxxx

    Option B — config file at ~/.config/gmail-mcp/client.json:

    { "client_id": "xxxxx.apps.googleusercontent.com", "client_secret": "GOCSPX-xxxxx" }

If credentials are missing, tools return an error pointing back at this section — the server itself never crashes over it.

Install & build

npm install
npm run build

The server binary is dist/index.js (stdio transport; all logging goes to stderr).

Hooking it up to Claude

Claude Code (~/.claude.json, or per-project .mcp.json) / Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "gmail": {
      "command": "node",
      "args": ["/absolute/path/to/gmail-mcp-server/dist/index.js"],
      "env": {
        "GMAIL_MCP_CLIENT_ID": "xxxxx.apps.googleusercontent.com",
        "GMAIL_MCP_CLIENT_SECRET": "GOCSPX-xxxxx"
      }
    }
  }
}

(Omit the env block if you use ~/.config/gmail-mcp/client.json.)

With Claude Code you can also add it from the CLI:

claude mcp add gmail -- node /absolute/path/to/gmail-mcp-server/dist/index.js

Running over HTTP (hosted)

node dist/index.js --http serves MCP over Streamable HTTP at /mcp, stateless, with a /healthz endpoint.

Env var

Default

Purpose

GMAIL_MCP_HTTP_TOKEN

required

Bearer token clients must send. At least 32 characters; the server refuses to start without it. Generate with openssl rand -hex 32.

GMAIL_MCP_HTTP_HOST

127.0.0.1

Interface to bind. Use 0.0.0.0 only behind a reverse proxy.

GMAIL_MCP_HTTP_PORT

3333

Port.

Requests without the right Authorization: Bearer … header get 401. The token check is constant-time.

Docker:

docker build -t gmail-mcp-server .
docker run -d -p 127.0.0.1:3333:3333 \
  -e GMAIL_MCP_HTTP_TOKEN="$(openssl rand -hex 32)" \
  -e GMAIL_MCP_CLIENT_ID=... -e GMAIL_MCP_CLIENT_SECRET=... \
  -v gmail-mcp-data:/data gmail-mcp-server

Tokens are stored under /data/.config/gmail-mcp/ in the volume.

Adding accounts on a hosted server. The consent flow opens a browser on the machine running the server, so it does not work remotely. Add accounts on your own machine with node scripts/add-account.mjs [--readonly | --send] [--alias name], then copy ~/.config/gmail-mcp/accounts.json into the volume.

Before exposing it to the internet:

  • Terminate TLS in front of it with Caddy, nginx, or a platform load balancer. Never send the bearer token over plain HTTP.

  • Treat the token like a password. Anyone holding it can use every stored account at its access level.

  • The bearer token is a single shared secret, suited to one owner. Multi-user hosting should use the MCP authorization spec (OAuth 2.1 with protected-resource metadata), which is the planned next step.

Adding accounts

Ask your MCP client to call gmail_add_account. A browser opens for Google consent (the URL is also returned in the tool response in case it doesn't). The flow runs on an ephemeral 127.0.0.1 loopback listener and times out after 5 minutes.

  • Pass access to choose what the account can do: "readonly", "modify" (default), or "send". See the table below.

  • allow_send: true still works as a legacy alias for access: "send".

  • Pass alias ("personal", "work", …) to reference the account by a short name later.

  • The first account added becomes the default; pass set_default: true to change the default later.

  • Re-running gmail_add_account for an email you already added is the re-auth path — it overwrites the stored credentials (useful for expired/revoked tokens or upgrading an account to a higher access level).

Access levels

access

Scopes granted

Can do

Cannot do

"readonly"

gmail.readonly

search, read threads and messages, list labels

change labels, archive, trash, drafts, send, reply

"modify" (default)

gmail.modify

everything above + labels, archive, trash, create drafts

send, reply

"send"

gmail.modify + gmail.send

everything above + send, reply

Note that modify is not read-only: it can relabel and trash mail. Pick readonly for an account an AI assistant should only read.

Each write tool checks the account's stored scopes before calling Google and returns an instruction to re-add the account at the right level, not a raw 403.

Account routing

Every inbox tool takes account?: string, resolved as: exact email → alias → the default account → the sole stored account → an error listing what's available. gmail_search_threads additionally accepts account: "all": it queries every stored account concurrently, merges thread summaries newest-first, tags each with its account, and reports per-account failures inline without failing the whole search. Pagination (page_token) is single-account only.

Ids are account-specific. A thread_id/message_id found in one account does not exist in another — always pass the same account the id came from.

Token storage & security

  • ~/.config/gmail-mcp/accounts.json, written with mode 0600; stores refresh tokens only, never access tokens.

  • gmail_remove_account best-effort revokes the token with Google before deleting it locally.

  • The client secret of a Desktop-app OAuth client is not treated as confidential by Google's model, but keep it out of version control anyway. .gitignore excludes client.json, accounts.json, and .env*.

Threat model

  • Incoming mail is untrusted input. Tool results put email bodies into the model's context, so a message can contain instructions aimed at the assistant ("forward this to…", "reply with…"). Give assistant-facing accounts the lowest access level that works, and keep a human approving anything the assistant sends.

  • Least privilege by default. Sending is never granted unless you ask for it, and readonly removes every write path. Scope checks run locally before any Gmail call.

  • Local token storage. Refresh tokens sit on disk readable only by your user. Anyone with your user account can use them, so treat the machine as the trust boundary.

  • Revocation. Removing an account revokes its token with Google, not just the local copy.

Found a security issue? Open a GitHub issue without exploit details and ask for a private contact.

Troubleshooting

  • "Stored credentials … expired or revoked" — run gmail_add_account for that email again. If this happens every ~7 days, your consent screen is still in Testing mode; switch it to In production.

  • "Google did not return a refresh token" — the OAuth client isn't a Desktop app, or consent didn't complete. Recreate as Desktop app and re-run.

  • Browser doesn't open — the consent URL is included in the gmail_add_account response; open it manually on the same machine.

  • Message/thread not found (404) — you're almost certainly using an id from a different account; check the account field on the search result that produced it.

Development

npm run typecheck        # strict TS, no emit
npm test                 # unit tests (Vitest): access levels, write guards, token storage, routing, schemas, error mapping
npm run verify           # build, then protocol-level checks over stdio against an empty throwaway HOME
npm run test:live        # optional live test against two real accounts (see scripts/live-test.mjs); not run in CI
npx @modelcontextprotocol/inspector node dist/index.js   # interactive inspection

CI (.github/workflows/ci.yml) runs typecheck, unit tests, the protocol checks, and a gitleaks secret scan on every push and pull request.

License

MIT, see LICENSE.

Available Tools

12 tools
gmail_add_accountAdd Gmail accountA

Add (or re-authenticate) a Gmail account via a browser OAuth consent flow on this machine.

Args:

  • access ("readonly" | "modify" | "send", default "modify"): readonly = search and read only; modify = read plus labels, trash, drafts; send = modify plus send and reply.

  • allow_send (boolean, legacy): same as access "send"; ignored when access is set.

  • alias (string, optional): short name usable anywhere an 'account' parameter is accepted.

  • set_default (boolean, default false): make this the default account. The first account added is always the default.

Returns: the authenticated email address and granted scopes. A browser window opens for consent; if it does not, the consent URL is included in the response for manual opening. Re-adding an existing email overwrites its stored credentials (this is the re-auth path).

Examples:

  • {"access": "readonly"} — add a read-only account

  • {} — add an account that can read, label, trash, and draft, but not send

  • {"access": "send", "alias": "work", "set_default": true}

Error Handling: returns an actionable error if OAuth client credentials are missing (see README setup), if the user denies consent, or if the flow times out (5 minutes).

ParametersJSON Schema
NameRequiredDescriptionDefault
aliasNoOptional short name for this account (e.g. 'personal', 'work').
accessNoAccess level. 'readonly' = search and read only (gmail.readonly). 'modify' = read plus labels, trash, drafts (gmail.modify). 'send' = modify plus send and reply. Overrides allow_send. Default 'modify'.
allow_sendNoLegacy flag, same as access: 'send'. Ignored when access is set. Default false.
set_defaultNoMake this account the default for calls that omit 'account'. The first account added always becomes the default.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide the safety profile, and the description adds substantial behavioral context: a browser window opens, a fallback consent URL is provided, re-adding overwrites existing credentials, and error conditions (missing OAuth client, denied consent, 5-minute timeout) are listed. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but organized into labeled sections (Args, Returns, Examples, Error Handling) with a one-line lead. Every section carries necessary information for a complex OAuth flow; nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 4 optional parameters, no output schema, and external side effects, the description is complete: it covers return values, side effects, auth behavior, timeouts, and errors. An agent has everything needed to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value with concrete usage examples, clarifies the legacy allow_send relationship, and explains that alias is usable anywhere an 'account' parameter is accepted — details that help an agent choose values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Add (or re-authenticate)'), the resource ('Gmail account'), and the mechanism ('browser OAuth consent flow'). This distinguishes it from sibling tools like gmail_remove_account and gmail_list_accounts without needing to open the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly identifies when to use the tool (initial setup or re-auth via OAuth) and explains the flow. It does not explicitly name alternatives or exclusions, but the sibling set makes the context unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_create_draftCreate Gmail draftA

Create a plain-text draft (saved to the account's Drafts folder; nothing is sent). Works without the send scope; needs access "modify" or "send" (gmail.modify).

Args:

  • to (string[], required), cc (string[], optional), bcc (string[], optional): recipient addresses.

  • subject (string, required), body (string, required): plain text.

  • account (string, optional): email or alias. Omit for the default account.

Returns: the draft id, its message id, and the account it was created in.

Examples:

  • {"to": ["alice@example.com"], "subject": "Draft: proposal", "body": "First pass..."}

  • {"to": ["b@x.com"], "subject": "Hi", "body": "...", "account": "personal"}

Error Handling: expired credentials return a re-auth instruction naming the account.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoCC recipients.
toYesRecipient email addresses.
bccNoBCC recipients.
bodyYesPlain-text draft body.
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
subjectYesDraft subject.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses that the draft is persisted to Drafts, requires modify/send scope, returns draft id/message id/account, and handles expired credentials with re-auth instructions. This gives the agent a solid model of side effects, auth needs, and failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized with a one-sentence purpose, grouped parameters, return value note, examples, and error handling. It is front-loaded with the most important behavioral information and every section earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given there is no output schema, the description fully covers return values, required/optional parameters, examples, account selection, and error behavior. An agent has enough information to construct valid calls and interpret results without missing critical context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description mostly restates schema details, though the examples add concrete usage patterns and clarify that 'account' can be an alias or omitted for the default account. This is helpful but not substantial new meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific action and resource: Create a plain-text draft saved to Drafts, with the explicit clarification that nothing is sent. This clearly distinguishes it from sibling tools like gmail_send_message and gmail_reply_to_thread.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for when to use the tool by noting drafts are saved but not sent and by specifying auth scope requirements. It does not explicitly name alternative tools or state when not to use it, but the distinction from sending is well implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_get_messageGet Gmail messageA
Read-onlyIdempotent

Fetch a single message with full body text and attachment metadata.

Args:

  • message_id (string, required): Gmail message id. Message ids are ACCOUNT-SPECIFIC — pass the same 'account' the id came from.

  • account (string, optional): email or alias. Omit for the default account.

  • response_format: 'markdown' (default) or 'json'.

Returns: normalized message (from/to/cc, date, subject, labels, body text) plus attachment metadata (filename, mimeType, size, attachment_id). Attachment CONTENT download is not supported in v1.

Examples:

  • {"message_id": "18c2f5a7b3d9e1f0"}

  • {"message_id": "18c2f5a7b3d9e1f0", "account": "personal", "response_format": "json"}

Error Handling: a 404 usually means the id belongs to a different account.

ParametersJSON Schema
NameRequiredDescriptionDefault
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
message_idYesGmail message id (account-specific).
response_formatNoOutput format: 'markdown' for compact human-readable rendering (default), 'json' for the full normalized structure.markdown

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, non-destructive behavior. The description adds meaningful behavioral context beyond that: message IDs are account-specific, attachment content download is not supported in v1, and a 404 usually indicates the ID belongs to a different account. These are non-obvious operational details that help an agent avoid mistakes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-organized with clear sections: a one-sentence summary, Args, Returns, Examples, and Error Handling. Every section contributes practical information, and the most important caveat (account-specific IDs) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description appropriately lists what the normalized message contains and what attachment metadata is included. It also covers the main error case and parameter defaults. For a simple read-only fetch tool with three parameters, this is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value by reinforcing the account-specific nature of message_id, explaining the response_format default and its effect, and giving concrete examples that clarify how parameters combine. This goes beyond the schema's own parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Fetch a single message with full body text and attachment metadata,' which is a specific verb plus resource and clearly distinguishes this from thread-level operations like gmail_get_thread. It also states what is included in the result, making the tool's purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear this is for fetching a single message, implies account context matters, and provides examples showing typical calls. It does not explicitly say 'use gmail_get_thread for a full thread' or 'use gmail_search_threads for searching,' so it lacks an explicit exclusion, but the context is clear enough to guide selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_get_threadGet Gmail threadA
Read-onlyIdempotent

Fetch a full thread — every message with normalized headers and body text.

Args:

  • thread_id (string, required): from gmail_search_threads. Thread ids are ACCOUNT-SPECIFIC — pass the same 'account' the id came from.

  • account (string, optional): email or alias. Omit for the default account.

  • response_format: 'markdown' (default) or 'json'.

Returns: all messages in the thread (from/to/cc, date, subject, labels, body text, attachment metadata). Long threads are truncated to fit the response limit, with a note saying how many messages were shown; use gmail_get_message for a specific message's full content.

Examples:

  • {"thread_id": "18c2f5a7b3d9e1f0"}

  • {"thread_id": "18c2f5a7b3d9e1f0", "account": "work", "response_format": "json"}

Error Handling: a 404 usually means the id belongs to a DIFFERENT account — check the 'account' field on the search result that produced the id.

ParametersJSON Schema
NameRequiredDescriptionDefault
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
thread_idYesGmail thread id (account-specific).
response_formatNoOutput format: 'markdown' for compact human-readable rendering (default), 'json' for the full normalized structure.markdown

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description adds meaningful behavioral context: truncated long threads with a note on message count, normalized headers/body, and a 404 failure mode tied to account mismatch. This goes well beyond what the annotations alone provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with front-loaded purpose, then Args, Returns, Examples, and Error Handling. Each section earns its place, and the content is detailed without being bloated or repetitive.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Since there is no output schema, the description properly explains return values: all messages with headers, body text, labels, and attachment metadata. It also covers truncation behavior and the likely 404 cause, so an agent has everything needed to invoke and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds actionable context: thread_id must come from gmail_search_threads and be used with the same account that produced it. The examples also clarify realistic invocation patterns, which exceeds the baseline without being redundant.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch a full thread — every message with normalized headers and body text.' It also distinguishes itself from siblings by stating it retrieves the complete thread and explicitly pointing to gmail_get_message for a specific message's full content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly establishes when to use this tool: to get an entire thread. It also gives an explicit alternative condition, 'use gmail_get_message for a specific message's full content,' and explains that thread_id comes from gmail_search_threads. It doesn't contrast with every sibling, but the routing guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_list_accountsList Gmail accountsA
Read-onlyIdempotent

List every stored Gmail account: email, alias, access level (read-only, read+modify, or read+modify+send), whether it is the default, and when it was added. Tokens are never exposed.

Args: none.

Returns: one line per account, or a note that no accounts are configured.

Examples:

  • {} — list all accounts

Error Handling: returns an error only if the local accounts file is unreadable or corrupt.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, but the description adds valuable behavioral detail: tokens are never exposed, output is one line per account, the no-accounts case is handled, and errors occur only if the local accounts file is unreadable or corrupt.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then organized into short labeled sections for args, returns, examples, and errors. Every section adds useful information without excessive wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read-only tool with no output schema, the description fully covers what the agent needs: invocation, return content, empty-result behavior, and error conditions. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters and the schema fully documents that with an empty properties object. The description reinforces this with 'Args: none' and a literal '{}' example, adding confirmation even though there is no parameter meaning to elaborate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'List every stored Gmail account,' followed by the exact fields returned. This clearly distinguishes it from sibling tools like gmail_list_labels and account-mutation tools such as gmail_add_account and gmail_remove_account.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is clear: call this when you need to enumerate stored accounts and their metadata. It does not explicitly name alternatives or exclusion criteria, but no other sibling provides account listing, so the context is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_list_labelsList Gmail labelsA
Read-onlyIdempotent

List every label in an account — system labels (INBOX, UNREAD, STARRED, SPAM, TRASH, ...) and user labels — with their ids. gmail_modify_labels operates on label IDS, so call this first to translate names to ids.

Args:

  • account (string, optional): email or alias. Omit for the default account.

  • response_format: 'markdown' (default) or 'json'.

Returns: label name, id, and type (system/user) for every label.

Examples:

  • {}

  • {"account": "work", "response_format": "json"}

Error Handling: expired credentials return a re-auth instruction naming the account.

ParametersJSON Schema
NameRequiredDescriptionDefault
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
response_formatNoOutput format: 'markdown' for compact human-readable rendering (default), 'json' for the full normalized structure.markdown

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description adds concrete return shape (name, id, type for every label) and credential-expiry behavior, going beyond the annotations. It does not contradict the annotations, and the only minor omission is explicit pagination/rate-limit behavior, which is not necessary for this simple read.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized with a purpose line, Args, Returns, Examples, and Error Handling, making it easy to scan. It is slightly redundant with the schema's parameter documentation, but every section earns its place and the most important guidance is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only listing tool with no required parameters and no output schema, the description covers purpose, parameter usage, return fields, example calls, and failure behavior. It also explains how the output relates to gmail_modify_labels, so nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents both parameters at 100% coverage, including defaults, enums, and account guidance. The description essentially restates the same account/response_format semantics without adding novel detail, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List every label') and a clear resource (a Gmail account), and it enumerates both system labels and user labels with IDs. It also differentiates itself from gmail_modify_labels by noting that the sibling operates on label IDs. This is specific, distinct, and not a tautology.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs the agent to call this tool first to translate label names to IDs before using gmail_modify_labels. It also clarifies account omission for the default account and includes error handling for expired credentials. This is direct when-to-use guidance with a named sibling alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_modify_labelsModify Gmail labelsA
Idempotent

Add and/or remove labels on one message or one whole thread. This is also how you archive and mark read/unread:

  • Archive: remove_label_ids: ["INBOX"]

  • Mark read: remove_label_ids: ["UNREAD"] · Mark unread: add_label_ids: ["UNREAD"]

  • Star: add_label_ids: ["STARRED"]

Args:

  • message_id OR thread_id (exactly one, required): target. Ids are account-specific.

  • add_label_ids (string[], optional), remove_label_ids (string[], optional): label IDS, not names — call gmail_list_labels to translate. At least one of the two is required.

  • account (string, optional): email or alias. Omit for the default account.

Returns: confirmation with the resulting label set (message) or affected thread id.

Examples:

  • {"message_id": "18c2...", "remove_label_ids": ["UNREAD"]}

  • {"thread_id": "18c2...", "add_label_ids": ["STARRED"], "remove_label_ids": ["INBOX"], "account": "work"}

Error Handling: unknown label ids return a Gmail error — list labels first. A 404 usually means the id belongs to a different account.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, and destructive hints. The description adds valuable behavioral context: account-specific IDs, the requirement of exactly one message_id or thread_id, and that at least one of add/remove is needed. It also describes the return value. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is organized with clear sections (Args, Returns, Error Handling) and includes two concise examples. While it is longer than typical, every sentence adds value—no filler or redundancy. The main purpose is front-loaded, and details are structured for easy scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema and limited annotations, the description is remarkably complete. It covers usage, parameter constraints, return values, error scenarios, and even practical tips like account-specific IDs. An agent could invoke this tool correctly without additional information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema is empty, so the description carries the full burden of parameter documentation. It thoroughly explains each parameter (message_id/thread_id, add_label_ids, remove_label_ids, account) with constraints, defaults, and the distinction between label IDs and names. This exceeds what a schema would typically provide.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Add and/or remove labels on one message or one whole thread.' It also explains that it is the mechanism for archiving and marking read/unread, and provides specific label IDs for those operations. This distinguishes it from sibling tools like gmail_trash_message and gmail_list_labels.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use the tool (e.g., to archive, mark read/unread, star) and how to translate label names to IDs via gmail_list_labels. It also includes error handling advice (list labels first, 404 suggests wrong account). While it doesn't explicitly contrast with siblings, the examples and notes make usage clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_remove_accountRemove Gmail accountA
DestructiveIdempotent

Remove a stored Gmail account by email or alias. Best-effort revokes the refresh token with Google, then deletes the local entry. If the removed account was the default, another stored account becomes the default (or the default is cleared).

Args:

  • account (string, required): email or alias to remove.

Returns: confirmation, including whether remote revocation succeeded and the new default account, if any.

Examples:

Error Handling: removing an unknown account returns an error listing available accounts. Revocation failures are ignored (the local entry is still deleted), making this safe to repeat.

ParametersJSON Schema
NameRequiredDescriptionDefault
accountYesEmail or alias of the account to remove.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructive and idempotent behavior, but the description adds substantial context: best-effort refresh-token revocation, local entry deletion, default-account reassignment/clearing, revocation failures being ignored, and repeat safety. This goes well beyond the annotations and gives an agent a clear model of 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.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized into concise sections (Args, Returns, Examples, Error Handling) with the main behavior front-loaded. Every sentence adds value—no padding—and the error-handling note is especially useful for a destructive tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, this description is complete: it covers behavior, return content, example invocations, and error cases. The annotations carry the destructive/idempotent profile, and the description fills in the rest. An agent has everything needed to invoke it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema description already documents the only parameter ('Email or alias of the account to remove'). The description's Args section repeats this without adding new semantics, though the examples provide useful formatting. Baseline 3 applies because the schema carries the semantic load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb+resource: 'Remove a stored Gmail account by email or alias.' This unambiguously identifies the operation and, alongside the sibling set (gmail_add_account, gmail_list_accounts), makes clear it is the removal counterpart. No ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear operational context—what revocation, deletion, and default-account behavior happen—but does not explicitly state when to use this tool vs. alternatives or when not to use it. However, the purpose is so specific that an agent can infer the appropriate context; it just lacks an explicit exclusion or alternative-naming statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_reply_to_threadReply to Gmail threadA

Reply to an existing thread from the account that owns it, with correct In-Reply-To/References threading headers. REQUIRES the account to have been added with access: "send".

Args:

  • thread_id (string, required): the thread to reply within (account-specific — use the same account the id came from).

  • body (string, required): plain-text reply body.

  • reply_all (boolean, default false): false replies only to the last message's sender (or Reply-To); true also includes everyone on that message's To/Cc lines (minus this account).

  • account (string, optional): email or alias. Omit for the default account.

Returns: confirmation echoing the sending account, recipients, and the new message id + thread id.

Examples:

  • {"thread_id": "18c2f5a7b3d9e1f0", "body": "Sounds good — Thursday works."}

  • {"thread_id": "18c2f5a7b3d9e1f0", "body": "Looping everyone in.", "reply_all": true, "account": "work"}

Error Handling: accounts without send access get a re-add instruction. A 404 usually means the thread id belongs to a different account.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesPlain-text reply body.
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
reply_allNoReply to all recipients of the last message instead of only its sender.
thread_idYesThread id to reply within (account-specific).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses key behaviors beyond the annotations: it creates threaded replies, requires send access, explains reply_all recipient semantics, specifies the return value, and covers common errors such as 404 indicating a cross-account thread id. This is substantial behavioral detail that annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized into Args, Returns, Examples, and Error Handling sections, with the purpose and access requirement front-loaded. It is longer than average but every section adds actionable information, and the examples clarify parameter usage without padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter tool with no output schema or output schema richness, this description is complete: it explains return values, error conditions, account requirements, recipient selection, and the exact threading behavior. An agent has enough context to call it correctly without needing the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds real semantic value beyond the schema: thread_id is account-specific, reply_all false means sender or Reply-To only, reply_all true includes To/Cc minus this account, account may be an alias, and examples illustrate realistic invocation. This goes well beyond the schema's field names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Reply to an existing thread'), the resource (thread, with threading headers), and a scope constraint ('from the account that owns it'). This clearly distinguishes it from siblings like gmail_send_message (new message) and gmail_create_draft (draft).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly specifies when to use the tool: to reply within an existing thread with correct In-Reply-To/References headers, and states the prerequisite that the account must have send access. It doesn't explicitly name alternatives like 'use gmail_send_message for new mail,' but the 'existing thread' framing provides clear context without naming siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_search_threadsSearch Gmail threadsA
Read-onlyIdempotent

Search threads with full Gmail search syntax, in one account or across all stored accounts.

Args:

  • query (string, required): Gmail search syntax. Examples: 'from:alice@example.com is:unread', 'newer_than:7d', 'has:attachment subject:"invoice"', 'to:me label:starred'.

  • account (string, optional): email or alias to search; the literal 'all' fans out to every stored account concurrently, merges results by date (newest first), and tags each thread with its account. Omit for the default account.

  • max_results (1–50, default 10): per-account cap.

  • page_token (optional): continue a previous single-account search. NOT supported with account:'all' — in that mode each account instead reports has_more; narrow the query or search one account to paginate.

  • response_format: 'markdown' (default) or 'json'.

Returns: thread-level summaries only (thread_id, account, participants, date, subject, snippet, message_count) — never full bodies. Use gmail_get_thread with the thread_id AND the same account to read a thread.

Examples:

  • {"query": "is:unread newer_than:2d"}

  • {"query": "subject:"invoice" has:attachment", "account": "all", "max_results": 20}

Error Handling: in 'all' mode, per-account failures are reported inline without failing the whole call. Expired credentials return a re-auth instruction naming the affected account.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesGmail search query (full Gmail search syntax). Examples: 'from:alice@example.com is:unread', 'newer_than:7d', 'has:attachment subject:"invoice"', 'label:important older_than:1m'.
accountNoEmail or alias to search, or the literal string 'all' to fan out across every stored account (results are merged by date and tagged with their account). Omit to use the default account.
page_tokenNoPagination token from a previous single-account search. Not supported with account: 'all'.
max_resultsNoMaximum threads to return (per account in 'all' mode). 1–50, default 10.
response_formatNoOutput format: 'markdown' for compact human-readable rendering (default), 'json' for the full normalized structure.markdown

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the description's confirmation of read-only behavior is redundant. However, it adds valuable behavioral details beyond annotations: the merge-by-date behavior across accounts, per-account caps, per-account failure handling, and the re-auth instruction behavior. It also clearly states what is NOT returned (full bodies), which is a behavioral boundary not covered by annotations. Minor deduction for not mentioning rate limits explicitly, but the added context justifies a strong score.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with an 'Args' section, examples, and error handling. It front-loads the primary purpose and then details parameters. It is somewhat long, but every section adds useful information. The explicit 'Returns' and 'Error Handling' sections are helpful. A 4 because it could be slightly more succinct without losing critical details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (multi-account fan-out, pagination limitations, partial failures), the description is remarkably complete. It covers input syntax, output shape, edge cases (page_token limitation), and error handling, so an agent has everything needed to invoke correctly. There is no output schema, so the description's 'Returns' section is essential and provided. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema fully documents each parameter with descriptions and examples. The description adds a few extra example queries and clarifies the behavior of page_token with account:'all', but these are marginal over the schema. A 3 is appropriate because the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Search') and resource ('threads'), and immediately clarifies the scope (full Gmail syntax, across accounts). It distinguishes itself from gmail_get_thread by noting it returns thread-level summaries only, directing the agent to the sibling for full content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit examples of when to use the tool and nuances like 'account: all' fan-out and pagination limitation, which are crucial for correct invocation. It also explains error handling in 'all' mode, so the agent knows failures are per-account and not fatal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_send_messageSend Gmail messageA

Send a new plain-text email from one of the stored accounts. REQUIRES the account to have been added with access: "send".

Args:

  • to (string[], required), cc (string[], optional), bcc (string[], optional): recipient addresses.

  • subject (string, required), body (string, required): plain text (v1 — no HTML, no attachments).

  • account (string, optional): email or alias to send FROM. Omit for the default account.

Returns: confirmation echoing the sending account, recipients, and the new message and thread ids.

Examples:

  • {"to": ["alice@example.com"], "subject": "Meeting notes", "body": "Attached below..."}

  • {"to": ["a@x.com"], "cc": ["b@x.com"], "subject": "Hi", "body": "...", "account": "work"}

Error Handling: if the account was added read-only, this returns an instruction to re-add it with access: "send" (use gmail_create_draft instead if the account should not send).

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoCC recipients.
toYesRecipient email addresses.
bccNoBCC recipients.
bodyYesPlain-text message body.
accountNoEmail or alias of the account to use. Omit to use the default account. Call gmail_list_accounts if unsure.
subjectYesMessage subject.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false and destructiveHint=false, and the description is consistent. It adds the requirement of 'send' access, describes the return confirmation (sending account, recipients, message and thread ids), and explains the error path for read-only accounts. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with Args, Returns, Examples, and Error Handling sections. The first sentence front-loads the core purpose. It is detailed but not redundant; every section adds information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 6 parameters and no output schema, the description covers the required access, parameter semantics, return format, error handling, and a routing alternative. An agent can confidently invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds value by providing concrete examples, clarifying the 'account' parameter as an email or alias with a default, and noting that cc/bcc are optional arrays. This goes beyond the schema's terse descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Send a new plain-text email from one of the stored accounts' – a specific verb and resource, and explicitly notes constraints (plain-text, no HTML/attachments) that distinguish it from siblings like gmail_create_draft and gmail_reply_to_thread.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states the prerequisite (account must have been added with access: 'send'), explains the default account behavior, and gives a clear alternative (gmail_create_draft) with the condition when to use it. The error handling section reinforces this.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_trash_messageTrash Gmail message or threadA
DestructiveIdempotent

Move one message or one whole thread to Trash. RECOVERABLE — Gmail keeps trashed mail for ~30 days and it can be restored from the Trash folder; nothing is permanently deleted by this tool.

Args:

  • message_id OR thread_id (exactly one, required): target. Ids are account-specific.

  • account (string, optional): email or alias. Omit for the default account.

Returns: confirmation of what was trashed and in which account.

Examples:

  • {"message_id": "18c2f5a7b3d9e1f0"}

  • {"thread_id": "18c2f5a7b3d9e1f0", "account": "personal"}

Error Handling: a 404 usually means the id belongs to a different account — check the 'account' field on the search result that produced the id.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds significant behavioral context beyond the annotations: it explicitly states the action is recoverable for ~30 days, can be restored from Trash, and that nothing is permanently deleted. It also describes return values and error behavior, giving the agent a full picture of what happens when invoked.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a leading purpose sentence, a highlighted recoverability note, a compact Args section, Returns, Examples, and Error Handling. Every section earns its place, and the most critical information (purpose and recoverability) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a moderate-complexity tool with no output schema, the description is complete: it covers the action, parameters, return value, examples, and error handling. It even addresses a common pitfall (id/account mismatch) with a concrete 404 explanation. Nothing an agent needs to invoke the tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema is empty, so the description carries the full burden for parameter meaning. It clearly specifies that exactly one of message_id or thread_id is required, defines ids as account-specific, and explains the optional account parameter. Examples demonstrate valid payloads, fully covering parameter semantics despite the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Move one message or one whole thread to Trash.' It also clarifies scope (one message or whole thread), which differentiates it from sibling tools like gmail_modify_labels or gmail_send_message. The purpose is unmistakable and distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: trashing is recoverable and not permanent, and it explains the required message_id/thread_id pattern. It does not explicitly mention when not to use the tool or compare it to alternative siblings, but the intended use is obvious and no exclusions are needed for this specific action.

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.

  1. 12 tool updatesv1.0.0
    • First observedgmail_add_account
    • First observedgmail_create_draft
    • First observedgmail_get_message
    • First observedgmail_get_thread
    • First observedgmail_list_accounts
    • First observedgmail_list_labels
    • First observedgmail_modify_labels
    • First observedgmail_remove_account
    • First observedgmail_reply_to_thread
    • First observedgmail_search_threads
    • First observedgmail_send_message
    • First observedgmail_trash_message

TDQS

A4.6/5.0

Scored across 12 tools

Disambiguation5/5

Every tool targets a distinct action-resource pair: account management, search/read, send/reply/draft, labels, and trash are cleanly separated. Even similar tools like get_message and get_thread are clearly scoped by resource type, and list_labels explicitly feeds modify_labels without overlap.

Naming Consistency5/5

All tools use the consistent gmail_verb_noun pattern with snake_case, making the action and target predictable. Minor variation like reply_to_thread instead of reply_thread does not break the overall convention.

Tool Count5/5

Twelve tools is well-scoped for a Gmail server: account lifecycle, search/read, send/reply/draft, labels, and trash each get focused coverage without redundancy. The count is solidly within the ideal range.

Completeness4/5

Core Gmail workflows are well covered: search, read, send, reply, draft, label modification, trash, and multi-account management. Minor gaps exist—no attachment content download, no draft editing/deletion, and no label create/delete—but these are workable and do not leave the main workflows dead-ended.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Connect multiple Gmail accounts to any MCP client, enabling search, read, draft, send, label, and organize mail across unlimited accounts with local-only OAuth token storage.
    22
    8 npm
    5
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables interacting with multiple Gmail accounts through a single MCP server, supporting search, labels, drafts, and thread management with per-account OAuth.
    1
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Multi-account Gmail MCP server for reading threads, managing labels, and creating drafts across multiple Gmail accounts.
    -