Skip to main content
Glama
smankoo

owlpost

owlpost

PyPI CI License: MIT smankoo/owlpost MCP server

A high-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail providers. Built because every other email MCP server I tried got tripped up by real-world IMAP quirks (CRLF line endings, RFC822 vs BODY.PEEK[], provider-specific Sent folders, multi-word search values).

owlpost is the one I actually use day-to-day from Claude Code to read, search, follow conversations, and send mail.

uvx owlpost

Contents

Related MCP server: email-mcp

Features

  • Multi-account — configure as many mailboxes as you want, switch by name

  • iCloud and Gmail tested end-to-end, with provider-specific quirks handled:

    • iCloud's RFC822 fetch returns empty bodies → uses BODY.PEEK[]

    • iCloud's IMAP APPEND requires CRLF line endings → all outbound mail uses policy.SMTP

    • iCloud's SMTP doesn't auto-save sent mail → owlpost APPENDs to Sent for you

    • Gmail's SMTP does auto-save → owlpost skips the duplicate APPEND

    • Folder names auto-discovered via RFC 6154 SPECIAL-USE (no hardcoding Sent Messages vs [Gmail]/Sent Mail)

    • Servers without the MOVE extension get COPY + \Deleted + EXPUNGE instead

    • Proton Bridge omits UID from FETCH responses unless asked → owlpost always asks

  • Conversation following — Gmail's X-GM-THRID extension where available, otherwise a generic Message-ID/References BFS across folders

  • Reliable connections — short-lived per-operation IMAP sessions instead of long-lived ones that drop randomly

  • MIME-aware — parses multipart messages, decodes headers, lists attachments, downloads them to disk

  • Threaded reply/forward — preserves In-Reply-To/References, quotes the original

  • Drafts — compose into the Drafts folder so you can review and send from your own mail client

  • Read-only by default where it matters — searching and reading never mark mail as read

  • Secrets stay out of the config file if you want — password_env and password_command (1Password, pass, Keychain, ...)

  • Annotated tools — every tool declares MCP readOnlyHint / destructiveHint / openWorldHint, so clients can auto-approve reads and ask before sending

Tools

Tool

What it does

Read-only

list_accounts

List configured mail accounts (never includes passwords)

✅

list_folders

List folders for an account, with detected special-use roles

✅

resolve_folder

Resolve a role (sent, trash, drafts, inbox, all, archive, ...) to the provider's folder name

✅

search_messages

Structured IMAP search (from/to/cc/subject/body/text/since/before/unseen/flagged/has_attachment, or raw), newest first

✅

read_email

Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits

✅

get_conversation

Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking)

✅

save_attachment

Download an attachment to local disk by part index (mailbox untouched)

writes local file

send_email

Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers

❌ sends

save_draft_email

Build a message and APPEND it to Drafts without sending — same parameters as send_email

❌

reply_email

Reply (with optional reply-all), preserving threading and quoting

❌ sends

forward_email

Forward, re-attaching original attachments by default

❌ sends

mark_read

Set/unset \Seen

❌

flag_message

Set/unset \Flagged (star)

❌

move_email

Move to another folder

❌ destructive

delete_email

Move to Trash (not expunged)

❌ destructive

Every tool takes an account argument (the name from list_accounts). Messages are addressed by folder + uid, as returned by search_messages.

Install

The recommended way is to not install at all — let uvx fetch and cache it on first use. This keeps the package always up-to-date and avoids polluting your global Python environment:

uvx owlpost            # speaks MCP over stdio
uvx owlpost --version

If you'd rather have a stable binary on your PATH:

uv tool install owlpost   # or: pipx install owlpost / pip install owlpost

There's also a container image, see Docker.

Configure

Copy accounts.example.toml to ~/.config/owlpost/accounts.toml and fill in your credentials. Use app-specific passwords, not your real password:

[accounts.icloud]
email = "you@icloud.com"
password_command = "op read op://Private/iCloud Mail/app-password"
provider = "icloud"
imap_host = "imap.mail.me.com"
smtp_host = "smtp.mail.me.com"
auto_save_sent = true   # iCloud SMTP doesn't auto-save sent

[accounts.gmail]
email = "you@gmail.com"
password_env = "OWLPOST_GMAIL_PASSWORD"
provider = "gmail"
imap_host = "imap.gmail.com"
smtp_host = "smtp.gmail.com"
auto_save_sent = false  # Gmail SMTP auto-saves

The table name (icloud, gmail above) is what you pass as account to the tools.

Where the config lives

In order of precedence:

  1. owlpost --config /path/to/accounts.toml

  2. the OWLPOST_CONFIG environment variable

  3. ~/.config/owlpost/accounts.toml

The file is read on the first tool call; restart the server after editing it.

Reference

Key

Required

Default

Meaning

email

✅

Login username and the From address

password

one of three

Password inline (app password recommended)

password_env

one of three

Name of an environment variable holding the password

password_command

one of three

Command that prints the password, e.g. op read op://...

provider

generic

icloud, gmail or generic. gmail enables X-GM-THRID threading

imap_host

✅

IMAP server hostname

imap_port

993

IMAP port

imap_security

ssl

ssl (implicit TLS, usually 993) or starttls (usually 143 / 1143)

smtp_host

✅

SMTP server hostname

smtp_port

587

SMTP port

smtp_security

starttls

starttls (usually 587) or ssl (usually 465)

auto_save_sent

true

APPEND a copy of sent mail to the Sent folder. Turn off for Gmail

tls_verify

true

Verify TLS certificates. Set false only for local bridges with self-signed certs

Exactly one of password, password_env and password_command must be set.

password_command is split with shell-like quoting rules and run directly (no shell, so no pipes or $VARS), with a 10 second timeout. Its stdout, minus the trailing newline, is the password. It runs the first time the account is used and the result is cached for the life of the server process. If it fails, the tool call returns an error with the command's exit code and stderr. Some examples:

password_command = "op read op://Private/Fastmail/app-password"                  # 1Password CLI
password_command = "pass show mail/fastmail"                                     # pass
password_command = "security find-generic-password -s owlpost-icloud -w"         # macOS Keychain
password_command = "secret-tool lookup service owlpost account icloud"           # GNOME Keyring

password_env reads the variable from the server's environment, which your MCP client controls (the env block in the snippets below).

Client setup

All of these run uvx owlpost. If your client can't find uvx, use the absolute path (typically ~/.local/bin/uvx, see which uvx). If you installed with uv tool install, you can use owlpost as the command instead.

Claude Desktop

One-click: download owlpost-<version>.mcpb from the latest release and open it. Claude Desktop installs it and asks for the path to your accounts.toml.

Manual:

Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "owlpost": {
      "command": "uvx",
      "args": ["owlpost"]
    }
  }
}

Claude Code

claude mcp add owlpost --scope user -- uvx owlpost

# with a non-default config path, or a password from the environment
claude mcp add owlpost --scope user \
  -e OWLPOST_CONFIG=/path/to/accounts.toml \
  -- uvx owlpost

Cursor

Add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):

{
  "mcpServers": {
    "owlpost": {
      "command": "uvx",
      "args": ["owlpost"]
    }
  }
}

VS Code

Add to .vscode/mcp.json in your workspace (or run MCP: Add Server for a user-level install):

{
  "servers": {
    "owlpost": {
      "type": "stdio",
      "command": "uvx",
      "args": ["owlpost"]
    }
  }
}

Other MCP clients

owlpost speaks the standard MCP stdio transport — any MCP-compatible client can talk to it by spawning uvx owlpost or the installed owlpost binary. Pass env: {"OWLPOST_CONFIG": "..."} to point it at a config file.

Docker

The image expects the config at /config/accounts.toml. Mount the directory that contains it, read-only:

docker run -i --rm \
  --mount type=bind,src="$HOME/.config/owlpost",dst=/config,readonly \
  ghcr.io/smankoo/owlpost:latest

As an MCP client entry:

{
  "mcpServers": {
    "owlpost": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--mount", "type=bind,src=/home/you/.config/owlpost,dst=/config,readonly",
        "ghcr.io/smankoo/owlpost:latest"
      ]
    }
  }
}

Inside the container password_command can only run binaries that exist in the image, so use password or password_env (pass it with -e OWLPOST_GMAIL_PASSWORD). To reach Proton Bridge on the host, use --network host (Linux) or imap_host = "host.docker.internal". save_attachment writes inside the container unless you mount a writable directory for it.

Examples

Once registered, you can ask things like:

  • "Find emails from the school about the field trip in the last month"

  • "Show me the full thread for the latest mortgage email"

  • "Reply to the most recent message from the landlord saying I'll be in touch tomorrow"

  • "Draft a reply to the insurance renewal asking for the PDF, don't send it"

  • "Forward the policy PDFs to you@example.com"

  • "Save the attachment from this month's electricity bill to ~/Downloads"

Provider notes

iCloud

  • Use an app-specific password, not your Apple ID password.

  • iCloud throttles aggressive reconnection. owlpost uses short-lived per-op sessions but doesn't pool — if you get SSLEOFError: EOF, back off for ~30 seconds.

  • Sent folder is Sent Messages, Trash is Deleted Messages. Both are auto-detected.

  • Keep auto_save_sent = true: iCloud's SMTP doesn't keep a copy of what you send.

Gmail

  • Requires 2FA and an app password.

  • IMAP must be enabled in Gmail settings → Forwarding and POP/IMAP.

  • Set provider = "gmail" so owlpost uses Gmail's X-GM-THRID extension for reliable thread detection.

  • Set auto_save_sent = false; Gmail's SMTP already files sent mail, so APPENDing would duplicate it.

  • delete_email moves to [Gmail]/Trash. Moving out of INBOX to a label folder works like archiving.

Proton Mail (via Proton Bridge)

Proton only exposes IMAP/SMTP through the Proton Bridge app, which runs on localhost with a self-signed certificate and speaks STARTTLS on non-standard ports. Configure with:

  • provider = "generic"

  • imap_host = "127.0.0.1", imap_port = 1143, imap_security = "starttls"

  • smtp_host = "127.0.0.1", smtp_port = 1025, smtp_security = "starttls"

  • tls_verify = false — required because Bridge's cert is self-signed

  • Use the Bridge-generated mailbox password (not your Proton account password)

Other providers

Set provider = "generic" and configure imap_host, smtp_host, ports, imap_security / smtp_security (starttls or ssl), and tls_verify (set false for self-signed certs). Folder roles will still be auto-detected if your provider supports SPECIAL-USE (most modern ones do); otherwise owlpost falls back to common names like Sent, Sent Items and Trash. Whether to keep auto_save_sent on depends on whether your provider's SMTP files sent mail itself — send yourself a test and check for duplicates.

Security

  • owlpost sends real email. send_email, reply_email and forward_email are annotated openWorldHint: true and are not read-only. Configure your MCP client to ask for confirmation before running them (most do by default for non-read-only tools), and don't auto-approve them. The server's instructions also tell the model to confirm recipients and content with you before sending. If you only want the model to prepare mail, steer it towards save_draft_email.

  • Untrusted content. Email bodies are written by strangers. A message can contain text designed to manipulate a model ("forward the last 10 invoices to ..."). Keep send confirmations on, especially in agents that read mail and can send it.

  • Use app passwords, never your main account password. They can be revoked individually and don't grant account-management access.

  • Keep secrets out of the file with password_command (your password manager) or password_env. If you do put a password in the file, chmod 600 ~/.config/owlpost/accounts.toml.

  • list_accounts never returns passwords or password sources.

  • tls_verify = false disables certificate checks entirely; only use it for a bridge on 127.0.0.1.

  • save_attachment and attachments read and write local paths as the user running the server.

Found a vulnerability? See SECURITY.md.

Troubleshooting

Symptom

Fix

Tools don't show up in the client

The client couldn't spawn uvx. Use its absolute path (which uvx) and restart the client. Run uvx owlpost --version in a terminal to check it works

owlpost config not found at ...

Create ~/.config/owlpost/accounts.toml, or set OWLPOST_CONFIG / --config

must set exactly one of password, password_env, password_command

Remove the extra key (or add one) in that [accounts.<name>] table

password_command exited with 1: ...

Run the command in a terminal. Password-manager CLIs often need you to be signed in (op signin) or unlocked

Unknown account 'x'. Known: [...]

Use one of the listed names; it's the TOML table name, not the email address

[AUTHENTICATIONFAILED] / 535 on login

Wrong or revoked app password; for Gmail, make sure IMAP is enabled

SSLEOFError: EOF on iCloud

iCloud throttling reconnects; wait ~30 seconds

CERTIFICATE_VERIFY_FAILED with Proton Bridge

Set tls_verify = false for that account

Sent mail appears twice

Your provider already saves sent mail; set auto_save_sent = false

Sent mail missing from Sent

Set auto_save_sent = true

unknown encoding: idna

Upgrade to owlpost 0.1.4 or later

Development

git clone https://github.com/smankoo/owlpost
cd owlpost
uv sync                      # creates .venv with dev tools
uv run pytest                # tests use fake IMAP/SMTP, no network
uv run ruff check .
uv run ruff format --check .
uv run python scripts/smoke_stdio.py uv run owlpost   # stdio handshake + tools/list

See CONTRIBUTING.md for the release process and CHANGELOG.md for history.

License

MIT — see LICENSE.

Available Tools

15 tools
delete_emailA
Destructive

Delete a message by moving it to the account's Trash folder.

The Trash folder is discovered via SPECIAL-USE (e.g. "Deleted Messages" on iCloud, "[Gmail]/Trash" on Gmail). The message is not permanently expunged from Trash, so it can still be recovered from the mail client.

Args: account: Account name from list_accounts. folder: Folder the message is currently in. uid: Message UID in that folder.

NameRequiredDescriptionDefault
uidYes
folderYes
accountYes

TDQS

A3.6/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and idempotentHint=false, but the description adds meaningful context beyond them: the operation is a soft delete (moved to Trash, not permanently expunged, recoverable from the client) and the Trash folder is discovered via SPECIAL-USE with concrete examples. Auth requirements and error behavior are still unstated.

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?

Front-loads the core action and its mechanism before the behavioral note and the Args block. The SPECIAL-USE parenthetical is slightly verbose but earns its place by pinning down the Trash resolution behavior; the Args block is justified given zero schema coverage.

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?

For a destructive mutation with annotations covering the safety profile and no output schema, the description supplies the key behavioral caveat (recoverable soft delete), parameter meanings, and folder-discovery detail. Missing only edge-case behavior (e.g., message not found, permission failures) to be fully complete.

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

Parameters4/5

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

With 0% schema description coverage, the description carries the full burden and documents all three params: account (sourced from list_accounts), folder (the message's current folder), and uid (the message UID within that folder). The account reference to list_accounts is a helpful pointer, though uid format and how to obtain it are not fully spelled out.

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?

States a specific verb and resource ('Delete a message') and immediately defines the mechanism ('by moving it to the account's Trash folder'), which usefully distinguishes it as a soft-delete rather than permanent removal. It does not explicitly name a sibling such as move_email, so the differentiation is implied rather than stated.

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 when-to-use or when-not-to-use guidance, and no reference to alternatives like move_email for relocation. Usage is only implied by the delete semantics; the recoverability note hints at consequences but is not framed as selection guidance.

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

flag_messageA
Idempotent

Flag (star) or unflag a message by setting or clearing its \Flagged flag.

Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. flagged: True to flag (default), false to remove the flag.

NameRequiredDescriptionDefault
uidYes
folderYes
accountYes
flaggedNo

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful context by explaining the exact underlying effect (setting/clearing the IMAP \Flagged flag) and the default behavior of the flagged argument.

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 opens with the core action and then lists parameters in a clean Args block. It is appropriately sized with no wasted sentences, though the two-part summary/args split is conventional rather than notably tight.

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?

With 4 parameters, no output schema, and annotations already covering the safety profile, the description provides what an agent needs to invoke it. The main gap is the absence of usage/routing guidance relative to sibling tools.

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

Parameters4/5

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

Schema description coverage is 0%, so the description carries the full burden and does document all four parameters. It usefully clarifies that flagged=true applies the flag while false removes it (and notes the default), though 'uid: Message UID' adds little beyond the schema title.

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?

States a specific verb (flag/unflag) and resource (message), and clarifies the mechanism (setting or clearing the \Flagged flag). It does not explicitly name or differentiate from similar siblings like mark_read, so it falls just 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 Guidelines3/5

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

Usage is implied by the tool's action rather than stated. The mention of 'Account name from list_accounts' gives a mild routing hint to a sibling, but there is no explicit when-to-use or when-not-to-use guidance.

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

forward_emailA

Forward a message to new recipients and send it immediately; confirm with the user first.

The subject gets a "Fwd:" prefix, the original headers and plain-text body are included below your note, and the original attachments are re-attached unless include_attachments is false.

Args: account: Account name from list_accounts. folder: Folder containing the message to forward. uid: UID of the message to forward. to: Recipient email addresses. body: Optional note placed above the forwarded content. cc: Cc recipient addresses. bcc: Bcc recipient addresses. attachments: Extra local file paths to attach. include_attachments: Re-attach the original message's attachments (default true).

NameRequiredDescriptionDefault
ccNo
toYes
bccNo
uidYes
bodyNo
folderYes
accountYes
attachmentsNo
include_attachmentsNo

TDQS

A4.3/5.0
Behavior5/5

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

Beyond the annotations (which only say it is a non-readOnly, non-destructive, non-idempotent open-world call), the description discloses the concrete outcome: automatic 'Fwd:' subject prefix, original headers and plain-text body inlined below the note, and original attachments re-attached unless include_attachments is false. It also states the message is sent immediately and requires user confirmation — exactly the context an agent needs for an irreversible external send.

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?

Purpose and the confirmation requirement are front-loaded, then content-transform behavior, then a parameter list that earns its space because the schema has no descriptions. Slightly verbose in the Args block, but nothing is wasted given the coverage gap.

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?

For a 9-parameter mutation tool with no output schema, the description covers what gets transformed, what gets sent, required confirmation, and parameter defaults. Gaps are minor: no statement of what the tool returns (sent message / UID), how folders should be resolved, or what happens on invalid recipients.

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?

With 0% schema description coverage across 9 parameters, the description carries the full burden and mostly meets it: it explains the distinction between 'attachments' (extra local files) and 'include_attachments' (re-attach originals, default true), the default for body, and cross-references list_accounts for the account value. The weaker spots are 'folder' (no hint that list_folders/resolve_folder produce it) and 'uid' (no format note).

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

Purpose5/5

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

The description opens with a specific verb and resource — 'Forward a message to new recipients and send it immediately' — and the word 'forward' plus 'to new recipients' cleanly distinguishes it from reply_email and send_email in the sibling list. An agent can select it without opening 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 Guidelines3/5

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

'Confirm with the user first' gives real pre-invocation guidance, which is valuable for an outward-facing send. However, there is no explicit statement of when to prefer forward_email over reply_email or send_email, and no prerequisites (e.g. needing to resolve the folder first via list_folders/resolve_folder).

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

get_conversationA
Read-onlyIdempotent

Return every message in the same conversation as a given message, oldest first.

On Gmail this uses the X-GM-THRID thread id across All Mail. Elsewhere it follows the Message-ID / In-Reply-To / References graph across the inbox, sent, archive, all-mail and drafts folders, so your own replies are included. Returns envelopes (no bodies); use read_email for content. Identify the seed message with either message_id, or folder + uid.

Args: account: Account name from list_accounts. message_id: Message-ID header of any message in the thread, including angle brackets. folder: Folder of the seed message (used with uid). uid: UID of the seed message (used with folder).

NameRequiredDescriptionDefault
uidNo
folderNo
accountYes
message_idNo

Output Schema

NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent/non-destructive annotations by describing the underlying mechanism on Gmail (X-GM-THRID across All Mail) versus other providers (Message-ID/In-Reply-To/References across inbox, sent, archive, all-mail, drafts), noting that the user's own replies are included, and disclosing that only envelopes are returned, no bodies.

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 core behavior and the read_email hand-off are front-loaded in the first paragraph, with provider-specific mechanics after. The Args block is slightly redundant in restating parameter names, but each line adds a semantic detail that the schema does not have.

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?

An output schema exists, so return values need not be explained, yet the description still flags the envelope-only return, which directly shapes downstream tool choice. With four params, empty schema descriptions, and a non-trivial provider-dependent thread algorithm, the description supplies everything an agent needs to call it correctly.

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

Parameters5/5

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

Schema description coverage is 0%, so the description carries the full burden and does so: `account` is sourced from list_accounts, `message_id` is the Message-ID header including angle brackets, and `folder`/`uid` are paired for seed identification. This is exactly the syntax detail the empty schema lacks.

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?

States a concrete verb and resource ('return every message in the same conversation as a given message, oldest first') with an ordering guarantee. It is clearly distinguishable from siblings like search_messages and read_email, and even notes the alternative tool by name.

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?

Explicitly instructs the agent to use read_email for message content, and tells it how to seed the lookup via either `message_id` or `folder` + `uid`. It lacks broader when-not-to-use guidance (e.g. when a simple search would suffice), but the content/thread routing is clear.

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 the mail accounts configured in owlpost's accounts.toml.

Returns one entry per account with its name (the value to pass as account to every other tool), email address, provider (icloud, gmail or generic), IMAP/SMTP hostnames and whether sent mail is auto-saved. Passwords and password sources are never included. Takes no arguments and does not contact any mail server.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

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

The annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description goes well beyond them: it discloses that no mail server is contacted (local file read), that passwords and password sources are never returned, and the exact per-account field set. 'Never included' is a meaningful security guarantee an agent cannot infer from schema or 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?

Front-loaded with the core action and data source, then the return shape, then the two key caveats (no passwords, no network). Every sentence carries distinct information; nothing is repeated from the schema or annotations.

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-argument, read-only discovery tool this is complete: the agent knows it needs no inputs, contacts no server, what each entry contains, and critically that the `name` field is the key to feed into all other tools. An output schema exists, so explaining return values further is unnecessary and the description does not overreach.

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?

Zero parameters, so the baseline is 4. The description correctly and explicitly confirms 'Takes no arguments', removing any ambiguity about whether an account filter is required, but there are no parameters whose semantics need further explanation.

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?

States a specific verb and resource (list accounts from accounts.toml) and enumerates exactly what each entry contains: name, email, provider, IMAP/SMTP hosts, auto-save flag. This clearly distinguishes it from the sibling set, which all operate on messages, folders, or attachments rather than accounts.

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?

Explicitly tells the agent that the returned `name` is 'the value to pass as `account` to every other tool', which effectively establishes this as the prerequisite discovery call. It also states it takes no arguments and does not contact any mail server, so the agent knows the cost profile. What's missing is an explicit 'call this first / before other tools' directive, though it is strongly implied.

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

list_foldersA
Read-onlyIdempotent

List every IMAP folder (mailbox) in an account.

Each entry has the folder name to use in other tools, its raw IMAP flags, the hierarchy delimiter, and a detected role (inbox, sent, trash, drafts, junk, archive, all, flagged, important) based on RFC 6154 SPECIAL-USE flags, or null for ordinary folders.

Args: account: Account name from list_accounts.

NameRequiredDescriptionDefault
accountYes

Output 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 readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile needs no restating. The description nonetheless adds real behavioral context: raw IMAP flags, hierarchy delimiter, and a role classification derived from RFC 6154 SPECIAL-USE flags with null for ordinary folders.

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?

Front-loaded with the action, then the return shape, then the argument. The parenthetical role enumeration is long but functional; the 'Args:' block is slightly formulaic for a single parameter, minor overhead only.

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 one-parameter, read-only list tool, everything an agent needs is present: what is listed, the identifier field to reuse downstream, the role vocabulary, and the parameter's origin. An output schema exists and annotations cover safety, so no further return-value or permission detail is owed.

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

Parameters4/5

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

Schema description coverage is 0% and the single parameter is documented only as a bare 'string' titled Account. The description compensates by defining it as 'Account name from list_accounts', which tells the agent where the valid value comes from rather than its format 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?

States a specific verb and resource ('List every IMAP folder (mailbox) in an account') and clarifies IMAP folder = mailbox. It also enumerates what each entry contains, so an agent immediately knows this is the folder-enumeration tool rather than a message-search or resolution tool.

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?

Usage is implied rather than stated: the entry's `name` is noted as the value 'to use in other tools', and `account` is sourced from list_accounts. There is no explicit when-to-use/when-not guidance or comparison against the closest sibling, resolve_folder, which serves a related folder-lookup purpose.

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

mark_readB
Idempotent

Mark a message as read or unread by setting or clearing its \Seen flag.

Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. read: True to mark read (default), false to mark unread.

NameRequiredDescriptionDefault
uidYes
readNo
folderYes
accountYes

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds genuine context by explaining the set/clear Seen-flag mechanism, which is why the operation is idempotent, but it says nothing about permission requirements, error behavior for a missing UID, or server-side effects.

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

Conciseness4/5

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

The purpose is front-loaded in one sentence and the argument list is tight with no filler. The Args block is slightly redundant with the schema but earns its place given zero schema description coverage.

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?

For a simple idempotent toggle with annotations covering the safety profile and no output schema, the description supplies everything needed to invoke it correctly: all four parameters, the default, and the resulting state change. Only return/error behavior is left implicit.

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

Parameters4/5

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

Schema description coverage is 0%, so the description must carry the full burden and largely does: it documents account (and its source, list_accounts), folder, uid, and the read flag with its default and inverted semantics. Only 'uid: Message UID' is tautological.

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?

States a specific verb and resource ('Mark a message as read or unread') and even names the underlying mechanism (the \Seen flag), so the effect is unambiguous. It does not, however, distinguish itself from the sibling 'flag_message', which an agent could plausibly confuse with this toggle.

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 never says when to use this tool versus 'flag_message' or when reading a message ('read_email') would be the alternative. The only routing hint is the parenthetical that 'account' comes from list_accounts, which is parameter provenance rather than usage 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 a message from one folder to another.

Uses IMAP MOVE when the server supports it, otherwise COPY followed by flagging the original \Deleted and EXPUNGE. The message gets a new UID in the destination folder, so the old uid is no longer valid afterwards.

Args: account: Account name from list_accounts. folder: Folder the message is currently in. uid: Message UID in that folder. dest_folder: Destination folder name (see list_folders).

NameRequiredDescriptionDefault
uidYes
folderYes
accountYes
dest_folderYes

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true, idempotentHint=false, and readOnlyHint=false. The description goes beyond them by disclosing the MOVE-vs-COPY+\Deleted+EXPUNGE fallback and, importantly, the post-condition that the message receives a new UID and the old uid is invalidated. It does not mention the EXPUNGE side effect on other flagged messages or any auth/permission requirements.

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?

Front-loaded with the core action, then mechanism, then parameter documentation. The Args block is somewhat boilerplate but earns its place given 0% schema coverage. No redundant or padded sentences.

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?

For a destructive mutation tool with no output schema, the definition covers the important state change (new UID, old uid invalid) and all inputs. What remains unstated is the return value and any error/permission failure modes, but the essentials for correct invocation are present.

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

Parameters4/5

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

Schema description coverage is 0%, so the description must carry the parameter burden, and it does: all four required params are explained, including provenance hints (account from list_accounts, dest_folder from list_folders) and the fact that folder is the message's current location. Minor gap: no note on uid format or whether it must be a string of digits.

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?

States a specific verb and resource ('Move a message from one folder to another') with unambiguous scope. It is clearly distinguishable from siblings like delete_email or flag_message by virtue of the move semantics, though it never names an alternative tool explicitly.

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 Args block implies prerequisites by pointing at list_accounts and list_folders for valid values, which is useful routing. However there is no explicit when-to-use guidance, no statement of when a move is preferable to delete_email plus send, and no mention of caveats such as insufficient permissions or read-only folders.

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

read_emailA
Read-onlyIdempotent

Read one message: decoded headers, body and attachment list, without marking it read.

By default only the plain-text body is returned, truncated at 50,000 characters to fit MCP result limits; the untruncated sizes are always reported as text_full_length and html_full_length. Attachments are listed with a 1-based part index for save_attachment. Threading headers (message_id, in_reply_to, references) are included.

Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID from search_messages. include_html: Also return the HTML body (default false). HTML mail can be very large. include_text: Return the plain-text body (default true). body_max_chars: Truncate each body to this many characters (default 50000).

NameRequiredDescriptionDefault
uidYes
folderYes
accountYes
include_htmlNo
include_textNo
body_max_charsNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial behavior context: default plain-text-only return, 50,000-char truncation to fit MCP limits, the always-reported text_full_length/html_full_length, and inclusion of threading headers. That is well beyond what the structured fields convey.

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?

Front-loaded with purpose and the key non-effect, then a well-organized Args block. Every sentence earns its place given the 0% schema coverage, though the prose section is a touch dense with parenthetical details.

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

Completeness5/5

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

For a 6-param, 3-required read tool with an output schema, the description covers inputs, defaults, truncation behavior, and safe-read semantics. Since an output schema exists, it needn't enumerate return fields, and nothing an agent needs to call it correctly is missing.

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

Parameters5/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 carry all parameter meaning, and it does: every one of the six args is documented with source hints (account from list_accounts, uid from search_messages), defaults, and rationale ('HTML mail can be very large'). This fully compensates for the schema 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?

States a specific verb and resource ('Read one message') plus the scope of what is returned (decoded headers, body, attachment list) and the key non-effect ('without marking it read'). This distinguishes it cleanly from siblings like search_messages, get_conversation, and mark_read.

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?

Explicitly routes the agent to sibling tools for its inputs ('Account name from list_accounts', 'Message UID from search_messages') and explains the 1-based `part` index is for save_attachment. It also implies mark_read is the alternative if you want read status changed. It lacks an explicit 'when not to use this' clause, but the context is clear.

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

reply_emailA

Reply to a message and send the reply immediately; confirm with the user first.

Addresses the reply to the original sender (plus the original To/Cc, minus your own address, when reply_all is true), prefixes the subject with "Re:" if needed, sets In-Reply-To and References so clients thread it correctly, and quotes the original plain-text body below yours.

Args: account: Account name from list_accounts. folder: Folder containing the message being answered. uid: UID of the message being answered. body: Your reply text; the quoted original is appended after it. reply_all: Also reply to the original To and Cc recipients. html: Optional HTML alternative for the reply. attachments: Local file paths to attach.

NameRequiredDescriptionDefault
uidYes
bodyYes
htmlNo
folderYes
accountYes
reply_allNo
attachmentsNo

TDQS

A4.5/5.0
Behavior5/5

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

Far exceeds what the annotations convey. It discloses recipient derivation ('original sender plus To/Cc minus your own address when reply_all is true'), subject mutation ('Re:' prefix if needed), threading header behavior (In-Reply-To and References), body quoting, and a confirmation requirement before sending. None of that is available from readOnlyHint=false / openWorldHint=true.

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 lead sentence is front-loaded and the Args block is scannable. The middle behavioral paragraph is a long compound sentence that packs several clauses together, but every clause carries information an agent needs, so it is dense rather than wasteful.

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?

A mutating, open-world tool with no output schema and seven parameters is fully covered: safety is handled by annotations, parameters are all explained, and side effects (threading, quoting, recipient set, confirmation) are disclosed. Nothing needed to call it correctly is missing.

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

Parameters5/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 carry the full burden, and it does: the Args block documents all seven parameters, including the cross-reference for account ('from list_accounts') and the non-obvious behavior of body ('the quoted original is appended after it').

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

Purpose5/5

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

The description states a specific verb and resource ('Reply to a message') and immediately pins down the mode ('send the reply immediately'), which separates it from save_draft_email and, by construction of threading headers and quoting, from send_email and forward_email. An agent can identify the tool's role without opening 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 Guidelines3/5

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

It gives one explicit directive ('confirm with the user first'), which is genuine usage guidance for an irreversible send. However, it never states when to choose reply_email over save_draft_email, send_email, or forward_email, nor any prerequisites beyond the account/folder/uid inputs.

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

resolve_folderA
Read-onlyIdempotent

Resolve a special-use role to the provider-specific folder name.

For example "sent" becomes "Sent Messages" on iCloud and "[Gmail]/Sent Mail" on Gmail. Uses SPECIAL-USE flags first and falls back to common folder names. Returns null if no matching folder exists.

Args: account: Account name from list_accounts. role: One of inbox, sent, trash, drafts, junk, archive, all, flagged or important (case-insensitive).

NameRequiredDescriptionDefault
roleYes
accountYes

Output 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 destructiveHint=false, so safety is covered. The description adds genuinely new behavior: the resolution strategy (SPECIAL-USE flags first, fallback to common folder names) and the failure mode (returns null if no matching folder exists). What is missing is any note on provider variance in failure or caching, but the disclosure goes well 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.

Conciseness4/5

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

The core behavior and example lead, followed by the fallback rule and null-return, then the arg notes — a sensible front-loaded order. The Args block is a small amount of overhead but earns its place given the 0% schema coverage.

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?

An output schema exists so return-shape explanation is unnecessary, and the description still covers the null case and both parameters. For a two-parameter resolver with full annotation coverage this is essentially complete; only explicit routing versus list_folders is absent.

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

Parameters4/5

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

Schema description coverage is 0% and neither parameter carries an enum in the schema, so the description does the heavy lifting: it enumerates the eight valid role values with a case-insensitivity note, and identifies account as 'Account name from list_accounts'. That is a large compensation for the schema gap, though it does not state the exact expected casing/format of the returned account string.

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?

States a precise verb+resource ('resolve a special-use role to the provider-specific folder name') and immediately grounds it with concrete examples ('sent' becomes 'Sent Messages' on iCloud, '[Gmail]/Sent Mail' on Gmail). This is unmistakably distinct from sibling tools like list_folders, which enumerate folders rather than map a role to a provider name.

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?

Usage is implied rather than stated: naming 'list_accounts' as the source of the account argument tells the agent the prerequisite chain, and the role vocabulary implies this precedes move_email/delete_email calls. However there is no explicit when-to-use statement and no exclusion versus list_folders, so the agent must infer the routing.

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

save_attachmentA
Idempotent

Download one attachment from a message and write it to the local filesystem.

The mailbox is not modified. Returns the written path, size, MIME type and original filename. An existing file at the target path is overwritten.

Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. part: 1-based part index from read_email's attachments list. save_to: Destination. A directory (trailing slash, existing directory, or a path without an extension) keeps the original filename; anything else is used as the full file path. ~ is expanded and missing directories are created.

NameRequiredDescriptionDefault
uidYes
partYes
folderYes
accountYes
save_toYes

TDQS

A4.7/5.0
Behavior5/5

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

With annotations only flagging readOnlyHint=false and idempotentHint=true, the description carries the real behavioral load and does so well: mailbox is not modified, an existing target file is silently overwritten (key data-loss risk), tilde is expanded, and missing directories are created. Return contents are also disclosed since no output schema exists.

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?

Purpose leads, behavior follows, then parameters — a sound front-loaded order with essentially no wasted words. The multi-line blank-separated prose layout is slightly heavier than needed for a tool description, but every sentence carries information.

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?

With no output schema, the description supplies the return values (path, size, MIME type, filename); with annotations covering the safety profile, it adds the overwrite warning and filesystem side effects. Nothing an agent needs to invoke this correctly is missing.

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

Parameters5/5

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

Schema coverage is 0%, so the description must carry all five required parameters, and it documents each one: account's source, folder/uid roles, part as a 1-based index from read_email, and save_to's directory-vs-file-path disambiguation with trailing-slash and extension heuristics. This is exactly the compensation a 0% schema demands.

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?

States a precise verb+resource+effect: download one attachment from a message and write it to the local filesystem. The singling out of 'one attachment' and the write-to-disk outcome clearly separate it from read_email, which merely lists parts.

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

Usage Guidelines4/5

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

It establishes the upstream workflow by tying `part` to read_email's `attachments` list and `account` to list_accounts, so an agent knows what must precede this call. It stops short of naming when-not-to-use cases or explicit alternatives, which is the only gap.

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

save_draft_emailA

Compose an email and save it to the account's Drafts folder without sending it.

The message is appended to the special-use Drafts folder with the \Draft flag, so the user can review, edit and send it from their own mail client. Use this instead of send_email whenever the user wants to check a message first. Each call creates a new draft.

Args: account: Account name from list_accounts. to: Recipient email addresses. subject: Subject line. body: Plain-text body. cc: Cc recipient addresses. bcc: Bcc recipient addresses. html: Optional HTML alternative to the plain-text body. attachments: Local file paths to attach. in_reply_to: Message-ID this draft replies to, for threading. references: Message-IDs of earlier messages in the thread.

NameRequiredDescriptionDefault
ccNo
toYes
bccNo
bodyYes
htmlNo
accountYes
subjectYes
referencesNo
attachmentsNo
in_reply_toNo

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=false, idempotentHint=false and destructiveHint=false, so the safety profile is covered. The description adds real context beyond that: the message is appended to the special-use Drafts folder with the \Draft flag, the user reviews/edits/sends from their own client, and 'Each call creates a new draft' independently confirms the non-idempotent behavior. It does not describe the return value or failure modes (e.g., invalid account, missing file), so not a full 5.

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?

Purpose is front-loaded, followed by behavior and then the argument list; every sentence earns its place and the size is proportionate to 10 parameters. The Args block is somewhat list-like, but each entry carries non-obvious meaning rather than restating the parameter name.

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?

For a 10-param mutation tool with no output schema and zero schema description coverage, the description covers the write path, folder placement, threading fields and the send-vs-draft decision well. Missing pieces are minor: nothing about what the call returns (e.g., a draft identifier) or which folders/accounts are valid beyond list_accounts.

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

Parameters4/5

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

Schema description coverage is 0%, so the description carries the entire burden, and it documents all 10 params with real semantics: account comes 'from list_accounts', html is an 'alternative to the plain-text body', attachments are 'Local file paths', and in_reply_to/references are explained in terms of threading. It stops short of format specifics (e.g., address string format, accepted date/ID syntax), so there is a small residual 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?

States a specific verb+resource ('Compose an email and save it to the account's Drafts folder without sending it') and immediately disambiguates from the closest sibling by name ('Use this instead of send_email'). An agent can distinguish it from send_email/reply_email/forward_email without opening any schema.

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

Usage Guidelines5/5

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

Gives an explicit selection rule: use this instead of send_email 'whenever the user wants to check a message first.' The alternative and the condition that selects it are both stated, leaving nothing to inference for the primary send-vs-draft decision.

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

search_messagesA
Read-onlyIdempotent

Search one folder with structured filters and return message envelopes, newest first.

All filters are combined with AND. String filters use IMAP case-insensitive substring matching; multi-word values are quoted for you. Each result has uid, folder, message_id, subject, from/to/cc, date, flags, size, seen and flagged; pass folder + uid to read_email for the body. The folder is opened read-only, so searching never marks mail read.

Args: account: Account name from list_accounts. folder: Folder to search (default "INBOX"); use list_folders or resolve_folder for others. from_: Substring of the From header (name or address). to: Substring of the To header. cc: Substring of the Cc header. subject: Substring of the Subject. body: Substring of the message body. text: Substring of headers or body. since: Only messages on or after this date (YYYY-MM-DD). before: Only messages before this date (YYYY-MM-DD). unseen: Only unread messages. seen: Only read messages. flagged: Only flagged/starred messages. has_attachment: Best-effort filter for messages with attachments (multipart/mixed or an attachment disposition header). raw: A raw IMAP SEARCH string, e.g. 'OR FROM "alice" FROM "bob"'. When set, every other filter is ignored. limit: Maximum number of results (default 50).

NameRequiredDescriptionDefault
ccNo
toNo
rawNo
bodyNo
seenNo
textNo
from_No
limitNo
sinceNo
beforeNo
folderNoINBOX
unseenNo
accountYes
flaggedNo
subjectNo
has_attachmentNo

Output Schema

NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

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

Goes beyond the readOnlyHint annotation with IMAP-specific behavior: the folder is opened read-only so searching never marks mail read, filters combine with AND, matching is case-insensitive substring with automatic quoting of multi-word values, and results are newest-first with a default limit of 50. The only gap is that it says nothing about pagination or how to page past the limit.

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 first sentence front-loads purpose, scope, and ordering before any detail, and the per-parameter list is dense and free of filler. Given 16 undocumented parameters, the length is justified rather than padded.

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

Completeness5/5

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

With an output schema present the return-value enumeration (uid, folder, message_id, subject, from/to/cc, date, flags, size, seen, flagged) is technically redundant, but it usefully tells the agent which fields are available for follow-up calls. Combined with the filter semantics and the read_email handoff, nothing needed to call this correctly is missing.

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

Parameters5/5

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

Schema description coverage is 0%, so the description carries the full burden and does: all 16 parameters are documented inline with meaning, defaults (INBOX, 50), date format (YYYY-MM-DD), and the non-obvious precedence rule that raw IMAP SEARCH overrides every other filter. This is exactly the compensation the low coverage requires.

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?

States a specific verb and resource ('Search one folder'), the filter model ('structured filters'), and the return shape ('message envelopes, newest first'). The 'one folder' scope plus the pointer to read_email for bodies lets an agent separate it from the sibling tools without opening a 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?

Gives concrete routing advice: use list_folders or resolve_folder to get non-default folders, and pass folder+uid to read_email for the body. It also flags the raw-parameter override rule. It does not, however, say when to prefer this over get_conversation or a plain folder listing.

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

send_emailA

Send a new email over SMTP immediately; this cannot be undone, so confirm with the user first.

When the account has auto_save_sent enabled (needed for iCloud, whose SMTP does not keep a copy) the message is also appended to the Sent folder. Returns the generated Message-ID, recipients and the folder the copy was saved to (null if none). To answer an existing message prefer reply_email, which fills in recipients and threading for you.

Args: account: Account name from list_accounts; mail is sent from its address. to: Recipient email addresses. subject: Subject line. body: Plain-text body. cc: Cc recipient addresses. bcc: Bcc recipient addresses (delivered but never written to headers). html: Optional HTML alternative to the plain-text body. attachments: Local file paths to attach. in_reply_to: Message-ID this message replies to, for threading. references: Message-IDs of earlier messages in the thread.

NameRequiredDescriptionDefault
ccNo
toYes
bccNo
bodyYes
htmlNo
accountYes
subjectYes
referencesNo
attachmentsNo
in_reply_toNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare the mutation profile (readOnlyHint=false, idempotentHint=false), and the description adds what they cannot: irreversibility, the user-confirmation requirement, the conditional Sent-folder append and why it exists (iCloud SMTP does not keep a copy), and the bcc header behavior. These are exactly the behavioral traits an agent needs before firing an irreversible write.

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?

Front-loaded with the irreversible-action warning and the sibling routing hint, then the side-effect behavior, then returns, then args. It is longer than most definitions but nearly every sentence carries new information; the args block is a necessary substitute for the 0%-coverage schema rather than padding.

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

Completeness5/5

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

With ten parameters, no output schema, and zero schema description coverage, the description compensates by documenting every argument and explicitly stating the return shape (Message-ID, recipients, saved folder or null). An agent has everything required to call and interpret this tool.

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

Parameters5/5

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

Schema description coverage is 0%, so the description carries the full burden and does so: all ten parameters are explained, including source provenance for account ('from list_accounts'), the privacy-relevant bcc note ('never written to headers'), and threading semantics for in_reply_to and references. Nothing is left as a bare name.

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 first clause gives a specific verb and resource (send a new email) plus the transport (SMTP) and immediacy. It also distinguishes itself from the sibling reply_email, so an agent can pick between them without opening either schema.

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

Usage Guidelines4/5

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

It gives a clear precondition ('confirm with the user first') and an explicit alternative for the most likely confusion case ('To answer an existing message prefer reply_email'). It does not cover the other near siblings (forward_email, save_draft_email) or say when not to send at all, so it stops short of full routing guidance.

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. 15 tool updatesv0.1.0
    • First observeddelete_email
    • First observedflag_message
    • First observedforward_email
    • First observedget_conversation
    • First observedlist_accounts
    • First observedlist_folders
    • First observedmark_read
    • First observedmove_email
    • First observedread_email
    • First observedreply_email
    • First observedresolve_folder
    • First observedsave_attachment
    • First observedsave_draft_email
    • First observedsearch_messages
    • First observedsend_email

TDQS

A4.2/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a clearly distinct action: listing vs. resolving folders, searching vs. reading, and four separate composition tools (send/reply/forward/draft) with explicit guidance on which to use. mark_read and flag_message operate on distinct IMAP flags, and move_email vs. delete_email are unambiguous. No two tools plausibly compete for the same selection.

Naming Consistency5/5

Every tool follows a consistent snake_case verb_noun pattern (list_folders, search_messages, read_email, send_email, reply_email, forward_email, move_email, delete_email). The few variations (get_conversation, mark_read, flag_message) still fit the verb-first convention. No mixed casing or verb-style drift.

Tool Count5/5

15 tools is well-scoped for a full IMAP/SMTP client. Each tool maps to a genuine mail operation (account/folder discovery, search, read, attachments, threading, compose variants, flag and folder operations) with no filler.

Completeness4/5

The surface covers the full email lifecycle: discovery, search, read, attachments, threading, send/reply/forward/draft, flags, move and trash. Minor gaps remain, notably folder creation/deletion and permanent expunge (delete intentionally moves to Trash), but core agent workflows are fully supported.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that enables AI models to read, search, and send emails via IMAP and SMTP protocols. It supports various providers like Gmail and Outlook, allowing for tasks such as retrieving unread messages, searching by sender, and managing mailbox folders.
    -
  • A
    license
    A
    quality
    D
    maintenance
    Local MCP server for multi-account IMAP/SMTP email (iCloud + Gmail via app-specific passwords). Never marks mail read. Cross-folder search, idempotent sends, TLS verified.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A unified MCP server for email access across Gmail, Outlook, iCloud, and generic IMAP providers, enabling search, send, organize, and batch operations.
    230 npm
    26
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Universal IMAP/SMTP MCP server that works with any email provider, providing tools to read, search, send, and manage emails.
    10
    242 npm
    1
    MIT