Skip to main content
Glama
LeoPhoenixT

readNdraft IMAP MCP

by LeoPhoenixT

readNdraft IMAP MCP

Safely search, read, flag, move, and draft email through IMAP. readNdraft can save and replace MCP-created drafts, but it cannot send, submit, or delete ordinary mail and contains no SMTP implementation.

Installation

1. Check the prerequisites

You need:

  • Windows 10/11 with Windows Credential Manager, or Linux with a working Secret Service-compatible keyring.

  • An IMAP account that permits password or app-password authentication using LOGIN or PLAIN over implicit TLS. OAuth is not implemented.

  • uv on PATH.

  • Codex, ChatGPT desktop, or Claude Code.

Confirm that uv is available:

uv --version

No repository clone or permanent readNdraft installation is required. uvx runs the published package in an isolated environment.

2. Configure an account

Run guided setup in a real interactive terminal:

uvx readndraft-imap-mcp@0.11.0 setup

This configures only readNdraft's local account, credential, and private state. Claude Code and Codex own their plugin, MCP registration, updates, and removal. ChatGPT desktop remains a separate manual MCP configuration target.

Client

Setup value

Detailed guide

Codex

codex

Codex and ChatGPT desktop

ChatGPT desktop

chatgpt-desktop

Codex and ChatGPT desktop

Claude Code

claude-code

Claude Code

Linux users should also follow the Linux platform guide to verify Secret Service and D-Bus before setup. Windows users can use the Windows platform guide.

The wizard will:

  1. Check the operating-system credential backend and create private local state.

  2. Ask for an account alias, IMAP host, port, username, and authentication method.

  3. Read the password or app password through a hidden terminal prompt.

  4. Test the IMAP connection before saving the account.

Never put an IMAP password in a command argument, environment variable, MCP configuration, issue, chat, or test report.

3. Install the marketplace plugin

The repository is the marketplace source; this is not GitHub Marketplace.

For Codex:

codex plugin marketplace add LeoPhoenixT/readNdraft-imap-mcp
codex plugin add readndraft@readndraft

For Claude Code, run these commands inside Claude Code:

/plugin marketplace add LeoPhoenixT/readNdraft-imap-mcp
/plugin install readndraft@readndraft

The plugin supplies one shared readndraft-email skill and a local stdio MCP definition pinned to readndraft-imap-mcp@0.11.0. It does not contain secrets, account data, or a send capability.

4. Restart and verify

Start a new client session after installing the plugin. Then run an online diagnostic from a terminal:

uvx readndraft-imap-mcp@latest doctor --online

For Codex, you can also confirm that the entry was loaded:

codex mcp get readndraft

Open a new task and ask: List my readNdraft accounts and mailboxes. A successful response confirms that the client can start the MCP and reach the local broker.

What setup stores

Item

Location or behavior

Runtime

Version-pinned by the plugin and run in uv's isolated cache.

Client integration

Marketplace/plugin state owned by Claude Code or Codex; it contains no IMAP password.

Agent Skill

readndraft-email, supplied by the installed plugin.

IMAP password

Stored only in Windows Credential Manager or the Linux Secret Service keyring.

Account metadata and app state

Stored in private per-user readNdraft application directories.

If setup reports a credential-backend or connection error, see Windows installation, Linux installation, and troubleshooting. The first MCP start may take longer while uv downloads the pinned package. If a stored password has changed, run uvx readndraft-imap-mcp account rotate-secret ALIAS.

Related MCP server: multi-email

What it can do

  • List administratively pinned accounts and mailboxes.

  • Search 1-500 results (50 by default) with explicit truncation, stable single-mailbox cursor pagination, per-target complete, partial, error, or pending status, attempted/pending legacy fields, selectable safe header fields, and server arrival timestamps. Attachment filename matching uses bounded MIME BODYSTRUCTURE metadata, never downloaded attachment payloads. Requests above 50 require one account and one mailbox.

  • Read safe headers and preferred plain text without setting the Seen flag. HTML-only messages are converted into a bounded, readable plain-text representation; get_email_html remains available for sanitized rich HTML. When the server supplies a valid MIME BODYSTRUCTURE, these reads fetch only the selected text section; malformed or nested-message structures use the existing bounded full-message fallback.

  • Batch-read plain text for up to 10 selected messages across 2 accounts.

  • Read strictly filtered HTML without loading remote content; remote-resource elements, attributes, and CSS are removed, and empty paragraphs are preserved.

  • Save one selected, bounded attachment into a fixed private output directory and return its absolute native-platform path. Attachment listings report nullable decoded size until a selected attachment is downloaded, plus nullable IMAP transfer-encoded encoded_size when BODYSTRUCTURE or exact wire bytes are known.

  • Star/unstar and mark read/unread without replacing unrelated flags.

  • Batch one star or read state across up to 50 selected messages and 3 accounts; batches return ordered per-item results.

  • Move one or up to 50 selected messages within one account. The broker prefers native UID MOVE and otherwise uses a private UIDPLUS COPY, source-only \Deleted, and targeted UID EXPUNGE sequence. Both source and destination must be existing selectable ordinary mailboxes; movement into or out of \Trash, \Junk, \Drafts, or \Sent SPECIAL-USE mailboxes is prohibited.

  • Create a plain-text or rich HTML server-side draft using bounded files from a fixed private input directory. Rich drafts require equivalent body plain text and optional html_body HTML. They are stored as multipart/alternative, with plain text first and HTML second, so modern mail clients normally display HTML while other clients retain a plain fallback. Rich input may be an HTML fragment or a complete HTML document. Supported authored CSS is permissive and inlined for broad mail-client compatibility. Draft requests are rejected when CSS could fetch remote resources, hide content, or escape the message box; empty paragraphs are always preserved. To, Cc, and Bcc may all be empty when the user wants an unaddressed draft. Each list item is one bare or named mailbox (for example, Ada <ada@example.com>). create_draft may receive an exact source message identity as reply_to_message to add safe reply threading; it does not derive recipients or rewrite subjects.

  • Update only a draft previously created by this MCP, after confirmation.

  • Inspect and repair local draft tracking with drafts list and drafts repair. drafts forget removes only the local tracking record; it never deletes or expunges the server message.

It exposes no send, submission, ordinary-message deletion, raw IMAP, arbitrary flag, credential, or account-administration MCP tool. Updating a tracked draft replaces it and expunges the previous draft version. A successful move reports its method and invalidates the source identity. Native MOVE may succeed without COPYUID, leaving the destination identity unavailable. The fallback requires COPYUID before marking the source deleted; otherwise it reports partial_move, retains the source, and requires both mailboxes to be reviewed. Never automatically retry an ambiguous move outcome.

Manual setup and administration

The setup wizard is recommended. Individual human-only commands are also available:

uvx readndraft-imap-mcp account add work --host imap.example.com --username login@imap.example.com --sender-address user@example.com --sender-name "Display Name"
uvx readndraft-imap-mcp account test work
uvx readndraft-imap-mcp account list
uvx readndraft-imap-mcp account set-sender work leo@example.com
uvx readndraft-imap-mcp account clear-sender work
uvx readndraft-imap-mcp account set-sender-name work "Display Name"
uvx readndraft-imap-mcp account clear-sender-name work
uvx readndraft-imap-mcp account rotate-secret work
uvx readndraft-imap-mcp account disable work
uvx readndraft-imap-mcp account enable work
uvx readndraft-imap-mcp account delete work

Passwords are accepted only through a hidden local prompt. Account configuration and credential operations are not MCP tools. username is the IMAP login identity; sender_address is the bare email address placed in the draft's From header and may differ from that username. If omitted or cleared, the address falls back to the username. sender_name is an optional display name, producing a header such as From: "Display Name" <user@example.com>; clearing it restores address-only behavior. MCP list_accounts exposes both effective sender settings so an agent can confirm them, but MCP cannot change or override them per draft. Downstream SMTP servers, mailing lists, and other mail systems may rewrite headers after the draft leaves the client; the MCP controls only the MIME draft it creates.

Configure ChatGPT desktop

Generate a secret-free configuration:

uvx readndraft-imap-mcp@latest configure chatgpt-desktop

This manual configuration path is retained for ChatGPT desktop, which is not covered by the Claude Code/Codex marketplace migration. The configure codex and configure claude-code forms remain temporarily available only for legacy 0.3.x compatibility and are not the normal installation path.

The unified mcp command uses the authenticated on-demand launcher. It reuses a healthy broker, starts exactly one when needed, and holds an authenticated lease while the MCP frontend is connected. A launcher-owned broker exits only after the final frontend disconnects and the idle period expires. Always-on systemd and Windows scheduled-task deployments remain available through the legacy administration documentation.

Upgrading from 0.3.x or earlier

Installing a plugin does not automatically remove an older user-scoped MCP entry, and that entry can override the plugin. First run the one-time migration for the client you previously configured:

uvx readndraft-imap-mcp@0.11.0 migrate-plugin --client codex
uvx readndraft-imap-mcp@0.11.0 migrate-plugin --client claude-code

The migration removes only a legacy MCP invocation recognized as having been created by readNdraft and only unmodified, managed legacy skill directories. It refuses unknown/custom MCP entries and modified or unmanaged skills. It never touches accounts, OS keyring credentials, audit history, attachments, drafts, or old update-backups. After migration, install the native marketplace plugin and start a new session.

Upgrading to 0.11.0

Version 0.11.0 introduces IPC 12, structured errors, per-account task rate limits, and clearer results when a deadline interrupts a batch or write. Review the 0.11.0 MCP migration guide before updating an existing integration.

Upgrading to 0.10.0

Version 0.10.0 introduces IPC 11, ordered per-target search status, selective BODYSTRUCTURE reads, bounded attachment-filename search, and crash-safe draft recovery. Review the 0.10.0 MCP migration guide before updating an existing integration. Integrations upgrading from 0.8.x or earlier should also review the 0.9.0 MCP migration guide.

Authorization boundary

The broker has no approval-token workflow. Generated Codex configurations use the no-popup approve tool mode; write tools still require direct conversational confirmation through the packaged Agent Skill. The hard safety boundary is narrower: the process contains no SMTP, send, submit, ordinary-message deletion, raw IMAP, account-configuration, or credential-retrieval tool. Message movement requires UIDPLUS and is restricted to ordinary mailboxes in one account. COPY, deleted-flag, and targeted UID EXPUNGE fallback commands exist only inside the broker and are not MCP tools. Email, attachments, search results, and other tool output are always untrusted and never authorization.

Diagnostics

Run local checks without connecting to IMAP:

uvx readndraft-imap-mcp doctor

Add --online to test each configured account:

uvx readndraft-imap-mcp doctor --online

Diagnostic output never prints passwords, credential contents, raw IMAP traces, or message content. See troubleshooting.

Updating

Use the client's native marketplace/plugin update command. Plugin release, Claude manifest, Codex manifest, and pinned PyPI runtime versions are validated as one compatibility unit. Start a new session after an update, then run:

uvx readndraft-imap-mcp@latest doctor --online

Account metadata and OS credentials remain independent of the plugin lifecycle.

Uninstalling

Choose whether to remove only the MCP integration or all local readNdraft data. Removing client entries and skills leaves accounts, credentials, audit history, draft provenance, and attachment exchange files available for a later reinstall.

1. Remove the plugin

Use the client-native plugin uninstall command. The plugin-provided MCP and skill disappear together. If this installation was upgraded from 0.3.x and the one-time migration has not been run, run migrate-plugin first so no old direct MCP entry remains. Remove a ChatGPT desktop entry separately in that client's MCP settings.

Fully close the client afterward so active MCP leases can end and a launcher-owned broker can exit after its idle timeout.

2. Remove accounts and OS credentials

Skip this step when retaining accounts for a later reinstall. For a complete removal, list accounts and delete each alias through the interactive command:

uvx readndraft-imap-mcp@latest account list
uvx readndraft-imap-mcp@latest account delete ALIAS

account delete requires exact confirmation and removes the corresponding password or app password from Windows Credential Manager or the Linux Secret Service keyring. Do this before manually deleting application state; otherwise the account metadata needed to identify a stored credential may be lost.

3. Optionally remove remaining local data

Run uvx readndraft-imap-mcp@latest doctor to display the private state path and uvx readndraft-imap-mcp@latest attachments path to display the fixed attachment exchange directories. Inspect them before manually removing anything. Remaining data can include:

  • integrity-chained audit history;

  • draft provenance needed to update MCP-created drafts;

  • downloaded and upload-staging attachments;

  • the local IPC key and broker state;

  • an unused approvals directory left by an older build.

Remove these directories only when their audit, recovery, and attachment data is no longer needed. readNdraft does not delete them automatically.

There is no permanently installed uv tool to uninstall when readNdraft is used only through uvx. uv may retain ordinary download/build cache entries shared with other tools; clearing uv's global cache is not required to uninstall readNdraft.

Security and privacy

The stdio MCP frontend cannot read the account file or OS credential store. It communicates over authenticated per-user IPC with a separate broker that enforces capabilities, quotas, provenance, and audit. Email and attachments are always untrusted input. Received HTML is sanitized for rich reads while preserving useful email structure, safe links, and a conservative set of presentation styles; HTML-only mail is converted to plain text for normal reads. Draft HTML is also sanitized and normalized before storage. It accepts common modern email markup, complete HTML documents, safe links, and allowlisted CSS; stylesheet rules are inlined for mail-client compatibility. Active content, event handlers, unsafe URL schemes, external stylesheets, and images cause draft creation or update to be rejected. Remote images, stylesheets, links, or other URLs are never fetched automatically. MCP tools never accept arbitrary local paths: draft files come only from the readNdraft attachment input directory and downloaded attachments are written only to its output directory. Run readndraft-imap-mcp attachments path to locate them. save_attachment also returns the saved file's absolute path using the MCP server host's native path format; clients must use that value verbatim.

Read SECURITY.md for the current security boundary. Security issues should not contain credentials or private mail.

IPC 12 pins request validation, structured nested SafeError records, and aggregate resource health data. Inspect error.code rather than matching error message text. A draft_busy result means another update holds the draft lock; recovery_required needs draft recovery before retrying; outcome_unknown means the IMAP write may have completed, so inspect the draft state instead of retrying automatically.

Development

See CONTRIBUTING.md before proposing a change. Security reports must use the private route documented in SECURITY.md.

uv sync --extra dev
uv run pytest
uv run python scripts/security_check.py
uv build --no-sources

Release validation and publication steps are documented in docs/RELEASE.md.

License

readNdraft, including its packaged Agent Skill and documentation, is licensed under the Apache License 2.0. Dependency licensing is summarized in THIRD_PARTY_NOTICES.md.

Available Tools

16 tools
create_draftB

Save a draft; authored HTML permits normal mail layout CSS but rejects remote resources, hidden content, and message-box escapes. Empty paragraphs are preserved. No send capability.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNo
toYes
bccNo
bodyYes
subjectYes
html_bodyNo
account_idYes
attachment_namesNo
reply_to_messageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
uidYes
mailboxYes
draft_idYes
account_idYes
message_idYes
uid_validityYes
attachment_hashesYes

TDQS

B3.2/5.0
Behavior4/5

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

Annotations are all false, so the description must carry behavioral context. It discloses that HTML is constrained (rejects remote resources, hidden content, message-box escapes), preserves empty paragraphs, and cannot send. These details add value beyond annotations and do not contradict them. It stops short of discussing result side-effects or failure modes, but is reasonably transparent.

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 three sentences in length, opens with the core action, and delivers key constraints efficiently. Every sentence adds meaningful information without repetition or filler.

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

Completeness2/5

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

Given the tool's complexity (9 parameters, 0% schema coverage), the description is inadequate. It fails to explain most required and optional parameters, so an agent cannot confidently construct correct calls. The presence of an output schema doesn't compensate for missing parameter semantics. Only the HTML-related behavior is covered.

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

Parameters2/5

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

With 0% schema description coverage, the description must compensate for all 9 parameters. It only touches on the html_body parameter through 'authored HTML' constraints and vaguely references content preservation. It offers no guidance on account_id, to, subject, body, cc, bcc, attachment_names, or reply_to_message, leaving most parameters poorly specified.

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

Purpose4/5

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

The description opens with 'Save a draft' – a specific verb and resource. It also clarifies 'No send capability,' which disambiguates from any sending tool. However, it does not explicitly differentiate from the sibling 'update_draft,' so it falls short of a 5.

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

Usage Guidelines2/5

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

There is no explicit guidance on when to use this tool versus alternatives like update_draft. The only hint is 'No send capability,' which implicitly rules out sending but doesn't name alternatives or conditions for selection. This leaves the agent to infer usage context.

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

get_emailC
Read-onlyIdempotent

Read safe headers/plain text using one complete returned identity.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
mailboxYes
account_idYes
uid_validityYes
max_text_charsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
textYes
flagsYes
headersYes
identityYes
attachmentsYes
text_truncatedYes
text_total_charsYes

TDQS

C2.3/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds that only 'safe headers/plain text' is read, which is useful context, but it does not clarify truncation, what 'safe' means, or any auth/rate-limit behavior.

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

Conciseness2/5

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

The description is extremely short for a tool with four required identity parameters and one optional content-limit parameter. It is not bloated, but it is under-specified to the point that brevity is a defect rather than conciseness.

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

Completeness2/5

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

An output schema exists, so return values need not be explained, and annotations cover safety hints. Still, the input identity is completely undocumented in both schema and description, and no usage context is supplied, leaving the definition inadequate for correct invocation.

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

Parameters1/5

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

There are five input parameters, four of them required, with 0% schema description coverage. The description does not explain account_id, mailbox, uid_validity, uid, or max_text_chars, and the vague phrase 'one complete returned identity' does not provide usable semantics for the identity tuple.

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

Purpose3/5

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

The description states a verb ('Read') and a narrow content type ('safe headers/plain text'), so it is not a bare tautology. However, it never names the resource as an email and does not distinguish itself from siblings such as get_email_html or get_emails, and the phrase 'using one complete returned identity' is opaque.

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

Usage Guidelines2/5

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

There is no when-to-use guidance, no when-not-to-use guidance, and no named alternative. The phrase 'using one complete returned identity' hints at a prerequisite identity from another call, but it does not identify which call or explain the selection context versus get_email_html, get_emails, or search_emails.

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

get_email_htmlA
Read-onlyIdempotent

Read strictly filtered HTML without remote loading; empty paragraphs are preserved.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
mailboxYes
account_idYes
uid_validityYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
htmlYes
flagsYes
identityYes

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral context: 'strictly filtered HTML without remote loading' discloses that remote content is not loaded (privacy/security feature), and 'empty paragraphs are preserved' indicates a specific formatting behavior. This goes beyond what annotations 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 a single sentence that is concise and front-loaded with the core purpose ('Read strictly filtered HTML'). Every word adds value: 'strictly filtered' and 'without remote loading' convey important behavioral constraints, and 'empty paragraphs are preserved' adds a specific detail. No wasted words.

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

Completeness4/5

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

The tool has an output schema (not shown in detail), which likely explains the return format, so the description doesn't need to cover that. The description covers the key behavioral aspects (filtering, no remote loading, empty paragraph preservation). Given the tool's moderate complexity (4 parameters, all required), the description is reasonably complete, though it could benefit from explaining the parameters or providing more context on when to use it.

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 0%, so the description must compensate for parameter meaning. However, the description doesn't explain any of the four parameters (account_id, mailbox, uid_validity, uid). The parameter names are somewhat self-explanatory (identifying an email), but the description adds no additional semantics beyond what the schema provides. With 0% coverage, the description should have provided more detail, but the parameters are standard email identifiers.

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

Purpose4/5

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

The description clearly states the tool reads filtered HTML from an email, specifying 'strictly filtered HTML without remote loading' and 'empty paragraphs are preserved'. It distinguishes itself from sibling tools like get_email and get_emails by focusing on HTML content with specific filtering behavior, though it doesn't explicitly name alternatives.

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

Usage Guidelines3/5

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

The description implies usage for retrieving HTML content with specific filtering requirements, but it doesn't explicitly state when to use this tool versus alternatives like get_email or get_emails. The context of 'strictly filtered' and 'without remote loading' suggests safety considerations, but no explicit when/when-not guidance is provided.

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

get_emailsA
Read-onlyIdempotent

Read plain text for 1-10 exact identities with ordered partial results.

ParametersJSON Schema
NameRequiredDescriptionDefault
identitiesYes
max_text_charsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

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

Annotations already cover read-only, idempotent, and non-destructive behavior. The description adds that results are plain-text and may be partial/ordered, but the phrase 'partial results' is vague and does not clarify truncation, pagination, or output limits.

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 a single dense sentence with no filler. It front-loads the core action and packs useful constraints into a compact form.

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

Completeness3/5

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

The description is adequate for a batch read operation but leaves ambiguity around the meaning of 'ordered partial results,' the effect of max_text_chars, and how this tool relates to get_email or search_emails.

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 0%, so the description must compensate. It clarifies that identities must be exact and limited to 1-10, but it does not explain the max_text_chars parameter or what 'partial results' means in relation to it.

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

Purpose4/5

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

The description states the action ('Read plain text'), the target resource ('emails' via exact identities), and the batch scope ('1-10 exact identities'). This distinguishes it from single-email retrieval and HTML retrieval, though it does not explicitly name sibling tools.

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?

'Exact identities' implies this tool is for known identifiers rather than search_emails, and 'plain text' distinguishes it from get_email_html. It provides clear context but does not explicitly state when not to use it or name alternatives.

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

list_accountsA
Read-onlyIdempotent

List safe account aliases. Call this before using an unknown alias.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds a small amount of context with 'safe' and the prerequisite guidance, but does not elaborate on return characteristics, ordering, or any other behavior beyond what annotations 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?

Two short sentences, front-loaded with the core action, and every word earns its place. The prerequisite instruction is direct and adds meaningful guidance without redundancy.

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 listing tool with a full output schema and safety-related annotations, the description is complete. It tells the agent what to call and when to call it, leaving no critical gaps.

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?

This tool has zero parameters, so the description does not need to explain parameter semantics. The baseline of 4 applies because there are no parameter-related gaps to compensate for.

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

Purpose4/5

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

The description clearly states the action ('List') and the resource ('safe account aliases'), making it distinct enough from sibling tools like list_mailboxes. It is concise and unambiguous, though it does not explicitly differentiate itself from all siblings.

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 instruction 'Call this before using an unknown alias' provides an explicit when-to-use recommendation. It does not mention when not to use it or compare it to alternatives, but the usage context is concrete and actionable.

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

list_attachment_inputsA
Read-onlyIdempotent

List safe files available in readNdraft's fixed attachment input directory.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare the tool as read-only, idempotent, and non-destructive. The description adds context beyond those by mentioning 'safe files' and the 'fixed attachment input directory', which clarifies the source and filtering behavior. It does not contradict annotations, though 'safe' is not further explained.

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 a single, concise sentence (12 words) that is front-loaded with the action 'List' and delivers all necessary information without wasted words.

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

Completeness4/5

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

This is a simple list operation with no parameters and an output schema available, so the description need not cover return values. The description provides the essential context (read-only, fixed directory, safe files), but leaves a minor gap by not defining what qualifies as 'safe'.

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?

The tool has zero parameters, so the baseline is 4. The description correctly omits parameter details, and the empty schema requires no additional semantics.

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 'List' and identifies a unique resource: 'safe files available in readNdraft's fixed attachment input directory'. This clearly distinguishes it from sibling tools like list_accounts or save_attachment, which target different resources.

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

Usage Guidelines3/5

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

The description implies usage context through the phrase 'attachment input directory', suggesting it is used to enumerate files available for attachments. However, it gives no explicit when-to-use or when-not-to-use guidance, nor does it mention alternatives among the sibling tools.

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

list_mailboxesA
Read-onlyIdempotent

List exact mailbox names for 1-10 accounts with isolated failures.

ParametersJSON Schema
NameRequiredDescriptionDefault
account_idsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, so the description does not need to repeat those. It adds meaningful behavioral context with 'isolated failures' and 'exact mailbox names,' which go beyond the 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 entire description is one short, front-loaded sentence that conveys purpose, scope, and failure behavior without any filler or redundancy.

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 read-only tool with an output schema and strong annotations, the description covers the essential information: what is listed, for how many accounts, and how failures behave. Nothing important 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 description coverage is 0%, so the description must compensate. It adds value by stating the account count range (1-10) and tying the behavior to accounts, but it does not clarify where account IDs come from or how invalid IDs are handled. Still, the single self-descriptive account_ids parameter keeps this adequate.

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 ('List'), a clear resource ('mailbox names'), and a precise scope ('for 1-10 accounts'). It distinguishes itself from the sibling tool list_accounts, which lists accounts rather than mailbox names.

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

Usage Guidelines3/5

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

The description implies the tool is used when you need exact mailbox names for up to ten accounts, but it does not explicitly mention when not to use it or suggest alternatives. The 'isolated failures' note provides some contextual expectation but not comparative guidance.

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

move_emailA
Destructive

Move one ordinary message to an existing ordinary mailbox.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
mailboxYes
account_idYes
uid_validityYes
destination_mailboxYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
methodYes
identityYes
destination_mailboxYes
destination_identityYes

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already indicate destructiveHint=true and readOnlyHint=false, so the agent knows this is a destructive write. The description adds the constraints that the destination must already exist ('existing') and that the message/mailbox are 'ordinary' (not special types), providing some extra context. However, it does not disclose details about source deletion or 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 a single, tightly worded sentence that front-loads the core purpose without filler. Every word contributes meaning.

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

Completeness2/5

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

Despite the annotations and output schema, the description is too sparse for a mutation tool with 5 required parameters and no parameter documentation. It lacks context on how to obtain the identifiers, the relationship between uid and uid_validity, and any prerequisites for moving an 'ordinary' message. The tool's overall behavior is underspecified.

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

Parameters2/5

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

Schema description coverage is 0%, and the description does not compensate. It mentions 'message' and 'destination_mailbox' but does not explain the meaning or format of uid, uid_validity, mailbox, or account_id. For a tool with 5 required params including the non-obvious uid_validity, this is a significant gap.

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 specific action ('Move'), the resource ('one ordinary message'), and the destination ('an existing ordinary mailbox'). The word 'one' distinguishes it from the batch sibling move_emails_batch, making its sole 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 Guidelines3/5

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

The singular 'one' implies this tool is for single-message moves, suggesting batch moves should go elsewhere, but it does not explicitly name alternatives or state when not to use this tool. The guidance is implied rather than explicit.

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

move_emails_batchA
Destructive

Move 1-50 ordinary messages from one account to one mailbox.

ParametersJSON Schema
NameRequiredDescriptionDefault
identitiesYes
destination_mailboxYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already indicate destructiveHint=true, idempotentHint=false, and readOnlyHint=false, so the mutating nature is covered. The description adds some useful behavioral context via the 1-50 count limit and the 'ordinary messages' restriction, but it does not disclose additional side effects, failure modes, or what happens if limits are exceeded.

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 a single, tightly worded sentence with no filler. It front-loads the action and resource, then adds the most operationally important constraints: quantity limit, message type, and source/destination scope.

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

Completeness3/5

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

The rich IdentityOutput schema and destructive annotations cover some context, and the description states the basic operation and limit. However, it omits how to obtain identities, how destination_mailbox should be formatted, and whether the batch is atomic or partially applied on failure, which matters for a destructive batch operation.

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

Parameters2/5

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, but it barely does. It does not explain that identities are an array of account/mailbox/UID references, how destination_mailbox is identified, or that all messages must come from one account despite each identity carrying its own mailbox field.

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 clear action ('Move'), a specific resource ('ordinary messages'), a quantity range ('1-50'), and the source/destination scope ('from one account to one mailbox'). The batch qualifier and count limit distinguish it from the singular move_email sibling 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?

The description gives clear usage context: this is the multi-message batch move tool with a 1-50 message limit and a single destination mailbox. It does not explicitly name move_email as the alternative for single messages, but the scope and limits imply the intended use well enough for an agent to route correctly.

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

save_attachmentC
Read-onlyIdempotent

Save one attachment; saved_path is its absolute native-platform location.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
mailboxYes
account_idYes
uid_validityYes
attachment_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
sizeYes
sha256Yes
saved_nameYes
saved_pathNo
content_typeYes
original_nameYes

TDQS

C2.5/5.0
Behavior1/5

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

The annotation declares readOnlyHint=true, but the description says 'Save one attachment,' implying a write operation to the filesystem. This is a direct contradiction, and the description does not clarify the tool's side effects, permissions, or overwriting behavior.

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 a single concise sentence that conveys the core function and a key output detail. It is efficient and well-structured, though it omits critical behavioral context.

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

Completeness1/5

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

Given the tool requires 5 parameters, has no parameter descriptions, and includes a contradictory annotation, the description is far from complete. It does not address usage context, side effects, or parameter relationships, making it inadequate for reliable tool invocation.

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

Parameters1/5

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

The input schema has 5 required parameters with 0% description coverage. The description does not explain the role of any parameter, relying solely on parameter names. This is insufficient for an agent to understand how to correctly populate the parameters.

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 saves one attachment and specifies that saved_path is the absolute native-platform location. This clearly defines the tool's action and distinguishes it from sibling tools like list_attachment_inputs or get_email.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives, nor any prerequisites or exclusions. It only describes the action without contextualizing its usage.

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

search_emailsC
Read-onlyIdempotent

Search 1-500 metadata rows in stable mailbox order with optional paging.

ParametersJSON Schema
NameRequiredDescriptionDefault
readNo
textNo
afterNo
limitNo
beforeNo
cursorNo
fieldsNo
senderNo
starredNo
subjectNo
targetsYes
recipientNo
attachment_filenameNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
orderYes
errorsYes
resultsYes
truncatedYes
next_cursorYes
target_statusesYes
targets_pendingYes
targets_searchedYes

TDQS

C2.9/5.0
Behavior4/5

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

The description adds valuable behavioral context beyond the annotations: results are limited to 1-500 rows, only metadata is returned, ordering is stable, and paging is supported. Annotations already cover safety (read-only, idempotent, non-destructive), so the added ordering and row-limit details are meaningful.

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 a single, compact sentence with no redundancy. It front-loads the most important behavioral facts (row range, metadata-only, stable order, paging). However, the extreme brevity comes at the cost of needed information, though that is better captured in contextual completeness.

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

Completeness1/5

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

This is a high-complexity tool with 13 parameters, a nested targets object, and zero schema descriptions, yet the description only offers a one-line summary. It fails to explain required targets structure, available filters, cursor semantics, limit behavior, or field selection, leaving an agent without enough information to call it correctly.

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

Parameters1/5

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

Schema description coverage is 0% and there are 13 parameters, yet the description names none of them and offers no explanation of targets, filters, cursor, limit, fields, or date constraints. The phrase 'optional paging' is the only parameter-related hint, which is far too little to compensate for the coverage gap.

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

Purpose4/5

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

The description clearly indicates a search operation over email metadata with concrete constraints: 1-500 rows, stable mailbox order, and optional paging. It goes beyond a bare restatement of the tool name, though it does not explicitly differentiate itself from similar siblings like get_emails.

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

Usage Guidelines2/5

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

No guidance is given on when to use this tool instead of alternatives such as get_emails or get_email. The only usage hint is 'optional paging,' but there is no when/when-not context, no mention of filter criteria usage, and no sibling routing.

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

set_read_stateC
Idempotent

Set one read state idempotently.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
readYes
mailboxYes
account_idYes
uid_validityYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stateYes
changedYes
enabledYes
identityYes
new_flagsYes
old_flagsYes

TDQS

C2.9/5.0
Behavior3/5

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

Annotations already declare idempotentHint=true, readOnlyHint=false, and destructiveHint=false. The description's 'idempotently' repeats the annotation, and the word 'one' adds minimal scoping context. It does not disclose additional behaviors like auth requirements or response semantics, but it does not contradict the annotations either.

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 a single concise sentence with no filler and front-loaded purpose. However, it is almost too sparse, functioning as a fragment rather than a complete thought, which slightly reduces clarity despite its efficiency.

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

Completeness2/5

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

Given 5 required parameters, including IMAP-specific uidd_validity concepts, no schema descriptions, and the existence of a batch sibling, the description is insufficient. It does not explain how to identify the message or when to prefer the single vs batch variant, leaving the tool under-documented for reliable use.

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

Parameters2/5

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

Schema description coverage is 0% and the description explains none of the 5 parameters. Terms like uid_validity and mailbox are left undefined, so the description fails to compensate for the sparse schema and offers little meaning beyond parameter names.

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

Purpose4/5

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

The description 'Set one read state idempotently.' uses a specific verb 'Set' and a clear resource 'read state', making the operation obvious. The word 'one' distinguishes it from the batch sibling set_read_state_batch, although it does not explicitly name the alternative, so it falls short of perfect sibling differentiation.

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

Usage Guidelines2/5

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

No guidance is given on when to use this tool versus set_read_state_batch or set_star. The singular 'one' implies a single-message use case, but there is no explicit context about prerequisites, exclusions, or alternatives, leaving the agent to infer usage.

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

set_read_state_batchA
Idempotent

Set one read state for 1-50 identities.

ParametersJSON Schema
NameRequiredDescriptionDefault
readYes
identitiesYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=false, destructiveHint=false, and idempotentHint=true, so the safety profile is covered. The description adds no behavioral context beyond the batch-size limit, which is acceptable given annotation coverage but not additive.

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 entire description is one short sentence that immediately states the action, resource, and batch scope. There is no redundant or filler text.

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

Completeness3/5

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

The schema and annotations cover parameter structure and behavioral safety, and the description supplies the batch-size limit, making the tool callable in principle. However, it lacks explicit usage guidance and does not articulate the read boolean's meaning beyond the schema, leaving modest gaps for an agent.

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

Parameters2/5

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

Schema description coverage is 0%, and the description does not compensate: it mentions 'read state' and 'identities' but does not explain the boolean 'read' parameter or the required IdentityOutput fields (account_id, mailbox, uid_validity, uid). An agent would need to infer the full parameter shape from the schema alone.

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 ('Set') with a clear resource ('read state') and scope ('1-50 identities'), and the batch qualifier distinguishes it from the singular set_read_state sibling. An agent can infer exactly what operation this performs.

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 '1-50 identities' range clearly describes the intended batching context, distinguishing it from the singular set_read_state sibling. However, it does not explicitly state when not to use this tool or mention alternatives by name.

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

set_starC
Idempotent

Set one starred state idempotently.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYes
mailboxYes
starredYes
account_idYes
uid_validityYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stateYes
changedYes
enabledYes
identityYes
new_flagsYes
old_flagsYes

TDQS

C2.7/5.0
Behavior2/5

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

The description says "idempotently," which merely repeats the idempotentHint annotation. It adds no new behavioral context such as authentication requirements, error behavior, or the effect on other email metadata. Since annotations already declare idempotency and non-read-only status, the description adds minimal value beyond structured data.

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 a single sentence with no wasted words. It is front-loaded with the operation (Set) and immediate qualifiers (one starred state, idempotently). Structurally, it is as concise as possible for the content it provides.

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

Completeness2/5

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

For a tool with five required parameters and no parameter documentation, the description is grossly incomplete. It lacks any mention of how to identify the target email, what the starred value means, or how to handle the response. While annotations cover idempotency and write behavior, they do not compensate for missing parameter context and usage instructions.

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

Parameters1/5

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

Schema description coverage is 0%, and the description provides zero explanation of the five parameters (account_id, mailbox, uid_validity, uid, starred). It does not indicate how these parameters relate to the email being starred, what the starred boolean controls, or how uid_validity is used. The tool is unusable without schema-level or description-level parameter semantics.

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

Purpose4/5

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

The description clearly states the tool sets one starred state, using the verb "Set" with a specific resource ("one starred state"). The qualifier "one" distinguishes it from the sibling set_star_batch, and "starred" separates it from set_read_state. While terse, it conveys the exact operation and primary scope.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives like set_star_batch or set_read_state. The description does not mention batch operations, read-state operations, or any exclusions or prerequisites, leaving the agent to infer usage from the name alone.

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

set_star_batchB
Idempotent

Set one starred state for 1-50 identities.

ParametersJSON Schema
NameRequiredDescriptionDefault
starredYes
identitiesYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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

Annotations provide idempotentHint=true and destructiveHint=false, but the description does not add context beyond 'set one starred state.' It doesn't clarify that repeated calls with the same parameters are safe (idempotent), nor what happens if an identity is invalid. For a batch mutation, some behavioral detail is expected, but the annotations cover the core safety profile, so this is adequate yet not rich.

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?

Single sentence, no fluff, distinctly states the operation and the batch size. Perfectly sized; could be longer only if it added critical behavioral context, but for a simple operation it's efficient.

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

Completeness3/5

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

Output schema exists (IdentityOutput) but is not referenced, and the description doesn't mention expected return values or errors. Given the tool's simplicity (only two params, one boolean), it is mostly complete, but it lacks guidance on how to obtain valid identities and what happens if any identity is invalid. With siblings like set_read_state_batch, more differentiation would help.

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 has 0% description coverage, and the description does not elaborate on 'identities' or 'starred.' It only says 'Set one starred state,' which implies the boolean semantics of 'starred' but provides no detail on how identities should be structured (though it's a nested object in the schema). Since the description is the only source and it's minimal, but the schema self-documents parameter names and types, a baseline 3 is appropriate.

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

Purpose4/5

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

Description clearly states the action ('Set one starred state') and resource ('1-50 identities'), making it distinct from batch operations like set_read_state_batch or move_emails_batch. It doesn't explicitly name a sibling, but the verb+resource is specific enough. However, it could mention that it's the batch variant of set_star.

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

Usage Guidelines3/5

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

The description implies batch usage (1-50 identities) and mentions the starred state, but provides no explicit guidance on when to use this versus set_star or set_read_state_batch. It doesn't state exclusions or prerequisites, such as whether identities must come from a prior list call. This left to inference; the limit itself is useful but not enough to fully route an agent.

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

update_draftB
Destructive

Replace a draft; authored HTML permits normal mail layout CSS but rejects remote resources, hidden content, and message-box escapes. Empty paragraphs are preserved. No send capability.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNo
toYes
bccNo
bodyYes
subjectYes
draft_idYes
html_bodyNo
account_idYes
attachment_namesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
uidYes
methodYes
mailboxYes
draft_idYes
account_idYes
message_idYes
uid_validityYes
attachment_hashesYes

TDQS

B3.1/5.0
Behavior4/5

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

Annotations already mark destructiveHint=true, and the description aligns by saying 'Replace a draft'. It adds valuable behavioral detail: HTML restrictions (permits normal layout CSS but rejects remote resources, hidden content, message-box escapes) and that empty paragraphs are preserved. It also clarifies it cannot send emails – useful context beyond 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?

Three sentences, with the primary purpose front-loaded. It adds only relevant details about HTML constraints and capabilities, with no verbosity. Every sentence earns its place, making it highly efficient.

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

Completeness2/5

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

For a complex tool with 9 parameters and 0% schema coverage, the description is thin. It covers purpose and HTML constraints but omits parameter semantics, required field explanations, and side effects beyond replacement. The presence of an output schema doesn't offset the missing parameter guidance, so completeness is low.

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

Parameters1/5

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, but it provides no information about any of the 9 parameters. It mentions 'authored HTML' but does not tie it to the html_body parameter. Required parameters like account_id, draft_id, to, subject, body are unexplained, leaving the agent without guidance on how to construct a valid call.

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

Purpose4/5

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

The description states 'Replace a draft' – a specific verb and resource. It clarifies scope with HTML constraints and 'No send capability', which helps distinguish from send-related tools. However, it does not explicitly name siblings like create_draft, though 'replace' implies updating an existing draft.

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

Usage Guidelines2/5

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

No explicit when-to-use guidance is provided. The description implies use for updating existing drafts rather than creating new ones, but does not state conditions or alternatives. It also omits prerequisites like having a draft_id, so an agent must infer usage context.

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. 6 tool updatesv0.11.0
    • Changedget_emails3 fields changed
      • changedOutput schema / $defs / BatchMessageOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / BatchMessageOutput / properties / error / title
        Removed value: -"Error"
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
    • Changedlist_mailboxes3 fields changed
      • changedOutput schema / $defs / MailboxBatchOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / MailboxBatchOutput / properties / error / title
        Removed value: -"Error"
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
    • Changedmove_emails_batch3 fields changed
      • changedOutput schema / $defs / BatchMoveOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / BatchMoveOutput / properties / error / title
        Removed value: -"Error"
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
    • Changedsearch_emails6 fields changed
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / SearchTargetErrorOutput / properties / error / $ref
        Added value: +"#/$defs/SafeErrorOutput"
      • removedOutput schema / $defs / SearchTargetErrorOutput / properties / error / title
        Removed value: -"Error"
      • removedOutput schema / $defs / SearchTargetErrorOutput / properties / error / type
        Removed value: -"string"
      • changedOutput schema / $defs / SearchTargetStatusOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / SearchTargetStatusOutput / properties / error / title
        Removed value: -"Error"
    • Changedset_read_state_batch3 fields changed
      • changedOutput schema / $defs / BatchFlagChangeOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / BatchFlagChangeOutput / properties / error / title
        Removed value: -"Error"
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
    • Changedset_star_batch3 fields changed
      • changedOutput schema / $defs / BatchFlagChangeOutput / properties / error / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "$ref": "#/$defs/SafeErrorOutput"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / BatchFlagChangeOutput / properties / error / title
        Removed value: -"Error"
      • addedOutput schema / $defs / SafeErrorOutput
        Added value: +{
        +  "properties": {
        +    "code": {
        +      "enum": [
        +        "partial_move",
        +        "permission_denied",
        +        "not_found",
        +        "invalid_request",
        +        "timeout",
        +        "rate_limited",
        +        "draft_busy",
        +        "recovery_required",
        +        "imap_error",
        +        "connection_error",
        +        "broker_error",
        +        "outcome_unknown"
        +      ],
        +      "title": "Code",
        +      "type": "string"
        +    },
        +    "message": {
        +      "title": "Message",
        +      "type": "string"
        +    },
        +    "reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "task_rate",
        +            "session_queue_timeout",
        +            "imap_worker_capacity",
        +            "ipc_helper_capacity",
        +            "request_deadline",
        +            "transport_loss"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Reason"
        +    },
        +    "retry_after_seconds": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Retry After Seconds"
        +    },
        +    "scope": {
        +      "enum": [
        +        "request",
        +        "item",
        +        "account",
        +        "broker",
        +        "client"
        +      ],
        +      "title": "Scope",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message",
        +    "scope",
        +    "reason",
        +    "retry_after_seconds"
        +  ],
        +  "title": "SafeErrorOutput",
        +  "type": "object"
        +}
  2. 3 tool updatesv0.10.0
    • Changedget_email4 fields changed
      • addedOutput schema / $defs / AttachmentMetadataOutput / properties / encoded_size
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "title": "Encoded Size"
        +}
      • addedOutput schema / $defs / AttachmentMetadataOutput / properties / size / anyOf
        Added value: +[
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / AttachmentMetadataOutput / properties / size / type
        Removed value: -"integer"
      • changedOutput schema / $defs / AttachmentMetadataOutput / required
        Previous value: -[
        -  "attachment_id",
        -  "filename",
        -  "content_type",
        -  "size"
        -]New value: +[
        +  "attachment_id",
        +  "filename",
        +  "content_type",
        +  "size",
        +  "encoded_size"
        +]
    • Changedget_emails4 fields changed
      • addedOutput schema / $defs / AttachmentMetadataOutput / properties / encoded_size
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "title": "Encoded Size"
        +}
      • addedOutput schema / $defs / AttachmentMetadataOutput / properties / size / anyOf
        Added value: +[
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / $defs / AttachmentMetadataOutput / properties / size / type
        Removed value: -"integer"
      • changedOutput schema / $defs / AttachmentMetadataOutput / required
        Previous value: -[
        -  "attachment_id",
        -  "filename",
        -  "content_type",
        -  "size"
        -]New value: +[
        +  "attachment_id",
        +  "filename",
        +  "content_type",
        +  "size",
        +  "encoded_size"
        +]
    • Changedsearch_emails3 fields changed
      • addedOutput schema / $defs / SearchTargetStatusOutput
        Added value: +{
        +  "properties": {
        +    "account_id": {
        +      "title": "Account Id",
        +      "type": "string"
        +    },
        +    "cursor": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Cursor"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Error"
        +    },
        +    "mailbox": {
        +      "title": "Mailbox",
        +      "type": "string"
        +    },
        +    "status": {
        +      "enum": [
        +        "complete",
        +        "partial",
        +        "error",
        +        "pending"
        +      ],
        +      "title": "Status",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "account_id",
        +    "mailbox",
        +    "status",
        +    "cursor",
        +    "error"
        +  ],
        +  "title": "SearchTargetStatusOutput",
        +  "type": "object"
        +}
      • addedOutput schema / properties / target_statuses
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/SearchTargetStatusOutput"
        +  },
        +  "title": "Target Statuses",
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "results",
        -  "errors",
        -  "next_cursor",
        -  "truncated",
        -  "order",
        -  "targets_searched",
        -  "targets_pending"
        -]New value: +[
        +  "results",
        +  "errors",
        +  "next_cursor",
        +  "truncated",
        +  "order",
        +  "targets_searched",
        +  "targets_pending",
        +  "target_statuses"
        +]
  3. 4 tool updatesv0.9.0
    • Changedget_email4 fields changed
      • addedInput schema / properties / max_text_chars
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Max Text Chars"
        +}
      • addedOutput schema / properties / text_total_chars
        Added value: +{
        +  "title": "Text Total Chars",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / text_truncated
        Added value: +{
        +  "title": "Text Truncated",
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "identity",
        -  "headers",
        -  "text",
        -  "flags",
        -  "attachments"
        -]New value: +[
        +  "identity",
        +  "headers",
        +  "text",
        +  "flags",
        +  "attachments",
        +  "text_total_chars",
        +  "text_truncated"
        +]
    • Changedget_emails4 fields changed
      • addedInput schema / properties / max_text_chars
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Max Text Chars"
        +}
      • addedOutput schema / $defs / MessageOutput / properties / text_total_chars
        Added value: +{
        +  "title": "Text Total Chars",
        +  "type": "integer"
        +}
      • addedOutput schema / $defs / MessageOutput / properties / text_truncated
        Added value: +{
        +  "title": "Text Truncated",
        +  "type": "boolean"
        +}
      • changedOutput schema / $defs / MessageOutput / required
        Previous value: -[
        -  "identity",
        -  "headers",
        -  "text",
        -  "flags",
        -  "attachments"
        -]New value: +[
        +  "identity",
        +  "headers",
        +  "text",
        +  "flags",
        +  "attachments",
        +  "text_total_chars",
        +  "text_truncated"
        +]
    • Changedlist_mailboxes5 fields changed
      • removedInput schema / properties / account_id
        Removed value: -{
        -  "title": "Account Id",
        -  "type": "string"
        -}
      • addedInput schema / properties / account_ids
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "title": "Account Ids",
        +  "type": "array"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "account_id"
        -]New value: +[
        +  "account_ids"
        +]
      • addedOutput schema / $defs / MailboxBatchOutput
        Added value: +{
        +  "properties": {
        +    "account_id": {
        +      "title": "Account Id",
        +      "type": "string"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Error"
        +    },
        +    "mailboxes": {
        +      "items": {
        +        "$ref": "#/$defs/MailboxOutput"
        +      },
        +      "title": "Mailboxes",
        +      "type": "array"
        +    },
        +    "ok": {
        +      "title": "Ok",
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "account_id",
        +    "ok",
        +    "mailboxes",
        +    "error"
        +  ],
        +  "title": "MailboxBatchOutput",
        +  "type": "object"
        +}
      • changedOutput schema / properties / result / items / $ref
        Previous value: -"#/$defs/MailboxOutput"New value: +"#/$defs/MailboxBatchOutput"
    • Changedsearch_emails5 fields changed
      • addedInput schema / $defs
        Added value: +{
        +  "SearchTargetInput": {
        +    "properties": {
        +      "account_id": {
        +        "title": "Account Id",
        +        "type": "string"
        +      },
        +      "mailbox": {
        +        "title": "Mailbox",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "account_id",
        +      "mailbox"
        +    ],
        +    "title": "SearchTargetInput",
        +    "type": "object"
        +  }
        +}
      • removedInput schema / properties / accounts
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "title": "Accounts",
        -  "type": "array"
        -}
      • removedInput schema / properties / mailboxes
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "items": {
        -        "type": "string"
        -      },
        -      "type": "array"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "default": null,
        -  "title": "Mailboxes"
        -}
      • addedInput schema / properties / targets
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/SearchTargetInput"
        +  },
        +  "title": "Targets",
        +  "type": "array"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "accounts"
        -]New value: +[
        +  "targets"
        +]
  4. 2 tool updatesv0.7.0
    • Changedcreate_draft2 fields changed
      • addedInput schema / $defs
        Added value: +{
        +  "IdentityOutput": {
        +    "properties": {
        +      "account_id": {
        +        "title": "Account Id",
        +        "type": "string"
        +      },
        +      "mailbox": {
        +        "title": "Mailbox",
        +        "type": "string"
        +      },
        +      "uid": {
        +        "title": "Uid",
        +        "type": "string"
        +      },
        +      "uid_validity": {
        +        "title": "Uid Validity",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "account_id",
        +      "mailbox",
        +      "uid_validity",
        +      "uid"
        +    ],
        +    "title": "IdentityOutput",
        +    "type": "object"
        +  }
        +}
      • addedInput schema / properties / reply_to_message
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/IdentityOutput"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
    • Changedlist_accounts1 field changed
      • addedOutput schema / $defs / AccountOutput / properties / sender_name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Sender Name"
        +}
  5. 2 tool updatesv0.5.0
    • Changedcreate_draft1 field changed
      • addedInput schema / properties / html_body
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Html Body"
        +}
    • Changedupdate_draft1 field changed
      • addedInput schema / properties / html_body
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Html Body"
        +}
  6. 4 tool updatesv0.3.0
    • Changedlist_accounts1 field changed
      • addedOutput schema / $defs / AccountOutput / properties / sender_address
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Sender Address"
        +}
    • Addedmove_email
    • Addedmove_emails_batch
    • Changedsave_attachment1 field changed
      • addedOutput schema / properties / saved_path
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Saved Path"
        +}
  7. 14 tool updatesv0.1.4
    • First observedcreate_draft
    • First observedget_email
    • First observedget_email_html
    • First observedget_emails
    • First observedlist_accounts
    • First observedlist_attachment_inputs
    • First observedlist_mailboxes
    • First observedsave_attachment
    • First observedsearch_emails
    • First observedset_read_state
    • First observedset_read_state_batch
    • First observedset_star
    • First observedset_star_batch
    • First observedupdate_draft

TDQS

A3.5/5.0

Scored across 16 tools

Disambiguation5/5

Each tool has a clear, distinct purpose. Batch and single variants (e.g., set_read_state vs set_read_state_batch) are explicitly differentiated, and get_email vs get_email_html vs get_emails serve different needs. No overlapping tools could cause selection confusion.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with snake_case, using 'batch' as a uniform suffix for multi-item operations. Examples like list_accounts, search_emails, set_star, and create_draft are predictable and uniform.

Tool Count5/5

16 tools is well-scoped for an IMAP server covering read, search, flag, move, draft, and attachment workflows. The count is neither bloated nor thin, and each tool contributes to the core functionality.

Completeness4/5

The surface covers most essential IMAP operations: reading, searching, flagging, moving, drafts, and attachments. However, there is no delete operation for emails or drafts, and no explicit trash handling, which are minor gaps for typical email workflows.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to search, read, and inspect Apple Mail on macOS, including conversations and attachments. It can create new, reply, reply-all, or forward drafts, but cannot send or modify existing messages.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables safe, multi-account Gmail and Microsoft 365 operations with explicit aliases, including searching, reading, drafting, archiving, labels/categories, and human-reviewed sending via a localhost approval window.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables read-only, provider-agnostic email access over IMAP, allowing users to list folders, search and read messages, and download attachments without ever marking messages as read.
    6
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables MCP clients to read, search, organise, and manage IMAP mailbox messages, including saving attachments and drafting replies, while treating mail content as untrusted and keeping write capabilities opt-in.
    6
    101 npm
    1
    MIT