owlpost
Allows reading, searching, following conversations, and sending mail through Gmail's IMAP/SMTP servers, utilizing Gmail's X-GM-THRID extension for reliable thread detection.
Allows reading, searching, following conversations, and sending mail through iCloud's IMAP/SMTP servers, with provider-specific quirks handled automatically.
Allows reading, searching, following conversations, and sending mail through Proton Mail via Proton Bridge, which provides local IMAP/SMTP endpoints.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@owlpostsearch my inbox for emails about the budget meeting"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
owlpost
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 owlpostContents
Client setup — Claude Desktop, Claude Code, Cursor, VS Code, Docker
Provider notes — iCloud, Gmail, Proton Bridge, generic
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
RFC822fetch returns empty bodies → usesBODY.PEEK[]iCloud's IMAP
APPENDrequires CRLF line endings → all outbound mail usespolicy.SMTPiCloud'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 Messagesvs[Gmail]/Sent Mail)Servers without the
MOVEextension get COPY +\Deleted+ EXPUNGE insteadProton Bridge omits
UIDfrom FETCH responses unless asked → owlpost always asks
Conversation following — Gmail's
X-GM-THRIDextension where available, otherwise a generic Message-ID/References BFS across foldersReliable 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 originalDrafts — 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_envandpassword_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 configured mail accounts (never includes passwords) | ✅ |
| List folders for an account, with detected special-use roles | ✅ |
| Resolve a role ( | ✅ |
| Structured IMAP search (from/to/cc/subject/body/text/since/before/unseen/flagged/has_attachment, or raw), newest first | ✅ |
| Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits | ✅ |
| Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking) | ✅ |
| Download an attachment to local disk by part index (mailbox untouched) | writes local file |
| Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers | ❌ sends |
| Build a message and APPEND it to Drafts without sending — same parameters as | ❌ |
| Reply (with optional reply-all), preserving threading and quoting | ❌ sends |
| Forward, re-attaching original attachments by default | ❌ sends |
| Set/unset | ❌ |
| Set/unset | ❌ |
| Move to another folder | ❌ destructive |
| 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 --versionIf you'd rather have a stable binary on your PATH:
uv tool install owlpost # or: pipx install owlpost / pip install owlpostThere'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:
iCloud: account.apple.com → Sign-In and Security → App-Specific Passwords
Gmail: myaccount.google.com/apppasswords (2FA must be enabled)
[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-savesThe table name (icloud, gmail above) is what you pass as account to
the tools.
Where the config lives
In order of precedence:
owlpost --config /path/to/accounts.tomlthe
OWLPOST_CONFIGenvironment variable~/.config/owlpost/accounts.toml
The file is read on the first tool call; restart the server after editing it.
Reference
Key | Required | Default | Meaning |
| ✅ | Login username and the | |
| one of three | Password inline (app password recommended) | |
| one of three | Name of an environment variable holding the password | |
| one of three | Command that prints the password, e.g. | |
|
|
| |
| ✅ | IMAP server hostname | |
|
| IMAP port | |
|
|
| |
| ✅ | SMTP server hostname | |
|
| SMTP port | |
|
|
| |
|
| APPEND a copy of sent mail to the Sent folder. Turn off for Gmail | |
|
| Verify TLS certificates. Set |
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 Keyringpassword_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 owlpostCursor
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:latestAs 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 isDeleted 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'sX-GM-THRIDextension for reliable thread detection.Set
auto_save_sent = false; Gmail's SMTP already files sent mail, so APPENDing would duplicate it.delete_emailmoves to[Gmail]/Trash. Moving out ofINBOXto 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-signedUse 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_emailandforward_emailare annotatedopenWorldHint: trueand 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 towardssave_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) orpassword_env. If you do put apasswordin the file,chmod 600 ~/.config/owlpost/accounts.toml.list_accountsnever returns passwords or password sources.tls_verify = falsedisables certificate checks entirely; only use it for a bridge on127.0.0.1.save_attachmentandattachmentsread 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 |
| Create |
| Remove the extra key (or add one) in that |
| Run the command in a terminal. Password-manager CLIs often need you to be signed in ( |
| Use one of the listed names; it's the TOML table name, not the email address |
| Wrong or revoked app password; for Gmail, make sure IMAP is enabled |
| iCloud throttling reconnects; wait ~30 seconds |
| Set |
Sent mail appears twice | Your provider already saves sent mail; set |
Sent mail missing from Sent | Set |
| 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/listSee CONTRIBUTING.md for the release process and CHANGELOG.md for history.
License
MIT — see LICENSE.
Available Tools
15 toolsdelete_emailADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| folder | Yes | ||
| account | Yes |
TDQS
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.
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.
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.
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.
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.
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_messageAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| folder | Yes | ||
| account | Yes | ||
| flagged | No |
TDQS
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.
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.
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.
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.
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.
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).
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | ||
| to | Yes | ||
| bcc | No | ||
| uid | Yes | ||
| body | No | ||
| folder | Yes | ||
| account | Yes | ||
| attachments | No | ||
| include_attachments | No |
TDQS
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.
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.
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.
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.
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.
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_conversationARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| uid | No | ||
| folder | No | ||
| account | Yes | ||
| message_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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_accountsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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_foldersARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| account | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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_readBIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| read | No | ||
| folder | Yes | ||
| account | Yes |
TDQS
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.
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.
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.
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.
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.
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_emailADestructive
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).
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| folder | Yes | ||
| account | Yes | ||
| dest_folder | Yes |
TDQS
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.
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.
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.
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.
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.
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_emailARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| folder | Yes | ||
| account | Yes | ||
| include_html | No | ||
| include_text | No | ||
| body_max_chars | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| body | Yes | ||
| html | No | ||
| folder | Yes | ||
| account | Yes | ||
| reply_all | No | ||
| attachments | No |
TDQS
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.
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.
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.
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.
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.
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_folderARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| role | Yes | ||
| account | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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_attachmentAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | ||
| part | Yes | ||
| folder | Yes | ||
| account | Yes | ||
| save_to | Yes |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | ||
| to | Yes | ||
| bcc | No | ||
| body | Yes | ||
| html | No | ||
| account | Yes | ||
| subject | Yes | ||
| references | No | ||
| attachments | No | ||
| in_reply_to | No |
TDQS
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.
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.
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.
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.
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.
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_messagesARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | ||
| to | No | ||
| raw | No | ||
| body | No | ||
| seen | No | ||
| text | No | ||
| from_ | No | ||
| limit | No | ||
| since | No | ||
| before | No | ||
| folder | No | INBOX | |
| unseen | No | ||
| account | Yes | ||
| flagged | No | ||
| subject | No | ||
| has_attachment | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | ||
| to | Yes | ||
| bcc | No | ||
| body | Yes | ||
| html | No | ||
| account | Yes | ||
| subject | Yes | ||
| references | No | ||
| attachments | No | ||
| in_reply_to | No |
TDQS
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.
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.
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.
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.
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.
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.
15 tool updates
v0.1.0- First observed
delete_email - First observed
flag_message - First observed
forward_email - First observed
get_conversation - First observed
list_accounts - First observed
list_folders - First observed
mark_read - First observed
move_email - First observed
read_email - First observed
reply_email - First observed
resolve_folder - First observed
save_attachment - First observed
save_draft_email - First observed
search_messages - First observed
send_email
TDQS
Scored across 15 tools
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.
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.
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.
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
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Your IMAP mailbox as an MCP server: read, search and (if you allow it) organize mail. Open source.
Hosted email MCP for your own Gmail, Outlook.com, Microsoft 365, iCloud or IMAP inbox: read, search, draft, reply in thread, forward and file mail. It moves or flags up to 500 messages in one call, and a send leaves exactly one copy in Sent. A calendar is a separate connection, and connecting one adds diary and scheduling tools.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn 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.-
- AlicenseAqualityDmaintenanceLocal 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.8MIT
- AlicenseNot gradedqualityBmaintenanceA unified MCP server for email access across Gmail, Outlook, iCloud, and generic IMAP providers, enabling search, send, organize, and batch operations.230 npm26MIT
- AlicenseBqualityCmaintenanceUniversal IMAP/SMTP MCP server that works with any email provider, providing tools to read, search, send, and manage emails.10242 npm1MIT