owlpost
Owlpost is a high-fidelity IMAP/SMTP MCP server designed to provide advanced, reliable email management across multiple accounts (iCloud, Gmail, etc.) while handling complex provider-specific quirks.
Search and read messages with structured, typed results, including body truncation and attachment listing.
Identify and retrieve full conversation threads by following Message-ID or using Gmail's X-GM-THRID.
Compose, draft, send, reply, and forward emails, preserving threading (In-Reply-To/References) and quoting.
Organize mail by moving messages, flagging, marking as read, and deleting emails (via Trash).
Download attachments from specific messages directly to the local disk.
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 foldersFast, reliable connections — logged-in IMAP sessions are reused for up to a minute (health-checked with NOOP, discarded after any error), every socket has a timeout, and read-only tools retry once if the server drops the connection
Typed results — every tool publishes an MCP output schema and returns structured content
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 reuses its IMAP session between calls to avoid this, but if you still see
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | |
| uid | Yes | |
| from | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, but the description adds genuinely non-obvious behavior: the destination is resolved via SPECIAL-USE (with concrete per-provider examples) and the message is not permanently expunged, so it remains recoverable from a mail client. This is meaningful context beyond the annotations, though it says nothing about failure modes (missing UID, folder not found) or behavior when the message is already in Trash.
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 its mechanism in the first sentence, with supporting detail after. The SPECIAL-USE parenthetical earns its place by explaining how the Trash folder is located, though the provider examples are slightly longer than strictly necessary.
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 3-parameter mutation with an output schema present, the definition covers what the action does, where the data goes, and the meaning of every parameter. Missing only edge-case behavior for invalid UID or already-trashed messages, which is a modest gap rather than a blocking one.
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 parameters, and its Args block does: account is tied to list_accounts, folder is defined as the message's current folder, and uid is the message UID within that folder. The docstring-dump args are spelled out even though the formal schema gives only titles, which is real compensation; a minor gap is that it doesn't state the expected UID format despite typing it as a 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 specific verb and resource ("Delete a message") and immediately defines the mechanism: it moves the message to the account's Trash folder rather than expunging it. That mechanism statement is what separates it from move_email in the sibling list, so an agent understands the distinction 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?
Usage is implied by the mechanism (soft delete, recoverable), but there is no explicit when-to-use vs. when-not, and no named alternative — notably it never says to prefer move_email for relocating a message somewhere other than Trash. An agent must infer that from the folder semantics.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| uid | Yes | |
| folder | Yes | |
| flagged | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, idempotent and non-destructive behavior, so the safety profile is covered. The description adds useful mechanism detail (the \Flagged IMAP flag and the default-on behavior of the flagged arg) but says nothing about permissions, error cases, or what the response contains.
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?
A single front-loaded sentence states the action, followed by a compact per-argument block. Every line is informative, though the Args section is a docstring rather than agent-oriented guidance.
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 and rich annotations, the definition needs mainly to cover parameters and mechanism, which it does. Minor gaps are lack of explicit sibling routing and any error/permission notes.
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% and every property is title-only, so the description carries the full burden and does so reasonably: it identifies account as coming from list_accounts, explains folder and uid roles, and clarifies that flagged defaults to true and false clears the flag.
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 pair (flag/unflag) and resource (message) plus the underlying mechanism of setting or clearing the \Flagged flag. It implicitly distinguishes itself from siblings like mark_read or move_email, though it never names them.
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 only implied by the verb; there is no explicit statement of when to choose flag_message over mark_read or other message-mutating siblings, and no prerequisites or exclusions are given.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | Yes | |
| to | Yes | |
| bcc | Yes | |
| from | Yes | |
| subject | Yes | |
| warning | No | |
| message_id | Yes | |
| size_bytes | Yes | |
| saved_to_folder | Yes | |
| refused_recipients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, openWorldHint=true, and idempotentHint=false, so the safety profile is partially covered. The description still adds real value beyond them: content transformation ("Fwd:" prefix, original headers and body below the note, attachments re-attached) and the confirm-first requirement. It does not state that repeated calls each produce a new outgoing email, so duplicate-send risk is only implied.
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 and the confirm-first rule are front-loaded, and the Args block is scannable with no filler. The two paragraphs are dense but every clause (prefix, headers, body placement, attachment default) conveys behavior an agent would otherwise have to guess.
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, and the description covers purpose, side effects, the confirm-first safety step, and every parameter for a 9-parameter mutation tool. Only edge behavior (invalid uid, missing attachments, failure modes on an open-world send) is left unstated.
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 its Args block does document all nine parameters, including the non-obvious ones (account from list_accounts, body as a note placed above forwarded content, include_attachments defaulting to true). It adds no format guidance for addresses or uid syntax, so not a full 5.
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 sentence names a specific verb and resource ("Forward a message") plus the immediate consequence ("send it immediately"), which distinguishes it from send_email, reply_email, and save_draft_email in the sibling list 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?
It gives a clear usage directive — "confirm with the user first" before an external, irreversible send — and the account/folder/uid framing shows it applies to existing messages. It stops short of explicitly directing the agent away from send_email/reply_email when those are the better fit.
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 annotations by disclosing implementation behavior: Gmail uses X-GM-THRID across All Mail, other providers traverse the Message-ID/In-Reply-To/References graph across inbox, sent, archive, all-mail and drafts. It also states the return shape (envelopes, no bodies), which the readOnly/idempotent hints do not 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 the core action and ordering, then provider behavior, then an Args block. Slightly redundant in restating parameter purposes after the prose, but every line carries information and there is no filler.
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 four-parameter, provider-varying lookup tool this covers the scope of the traversal, the seed identification paths, and the envelope-only return, so an agent can call it correctly without opening the schema. Output schema exists, so no further return-value explanation is required.
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 carries the full burden and does: it documents all four parameters, including the format detail that message_id includes angle brackets, and the pairing semantics of folder + uid. It also states the seed may be identified by either message_id OR folder+uid, a mutual-exclusivity rule the schema does not encode.
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 (return every message in the same conversation as a given message) plus an ordering guarantee (oldest first). It is clearly distinguishable from siblings like read_email and search_messages, which is reinforced by naming read_email for body content.
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 a clear use context (thread/conversation expansion) and an explicit alternative for a different need: 'use read_email for content.' It does not explicitly contrast with search_messages or state when-not to use it, so it falls short of full when/when-not/alternatives coverage.
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?
Goes beyond the annotations by disclosing the data source (a local accounts.toml), that no mail server is contacted, and — security-relevant and not in annotations — that passwords and password sources are never included. The no-network fact partly overlaps openWorldHint=false, so it is strong rather than exceptional.
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 verb and resource, then a tight enumeration of return fields, then two clarifying limitations. No filler sentences; every clause carries information an agent needs.
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, yet the description still summarises the entry shape and explicitly names the field that unlocks all other tools. For a zero-argument, read-only discovery tool, nothing further is required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which sets the baseline at 4. The description confirms 'Takes no arguments', consistent with the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the mail accounts configured in owlpost's accounts.toml') and enumerates exactly what each entry contains (name, email, provider, IMAP/SMTP hosts, sent-mail auto-save). It is unmistakably distinct from every sibling tool, which all operate on folders or messages rather than the account config.
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: the returned `name` is 'the value to pass as `account` to every other tool', which tells an agent to call this first before search_messages, read_email, etc. No when-not guidance is given, but for a zero-argument config readout there is no realistic alternative to exclude.
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 readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds real value by explaining how the folder `role` is derived (RFC 6154 SPECIAL-USE flags) and that it is null for ordinary folders, which is behavior an agent could not infer from annotations or the schema.
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 the purpose, and the entry-format paragraph is dense with useful detail. The 'Args:' block for a single parameter is slightly formal overhead but earns its place by naming the sibling source of the value.
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 one required parameter, a full annotation set and an output schema, the description covers what is needed: the source of the account argument and the shape/meaning of the returned folder metadata. It stops short of mentioning failure modes (bad account name, auth errors) that would make it fully self-sufficient.
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 for the single `account` parameter. It does clarify the expected value as an 'Account name from list_accounts', which identifies both the source and the format, but no further constraints (casing, aliasing) are given.
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, with 'mailbox' disambiguating the term. It does not distinguish itself from the sibling resolve_folder, which plausibly overlaps in purpose, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implies intended usage by noting the returned folder `name` is what you pass to other tools, establishing this as an entry-point/discovery call, and it points at list_accounts for the required argument. It gives no explicit when-to-use versus when-not-to-use guidance, and never contrasts with resolve_folder.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| uid | Yes | |
| seen | Yes | |
| folder | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds real value by disclosing that the operation is a \Seen flag toggle rather than a content change, but says nothing about permission requirements, server sync, or what happens on an invalid uid.
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 sentence is front-loaded and the Args block is a compact, scannable list. Some redundancy with the schema exists, but given 0% schema coverage that repetition earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the tool is simple. Still missing are the call-chain guidance (resolve_folder for the folder path, search_messages for the uid) and the behavior when the UID does not exist, which matter for a four-parameter mutation.
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 it does enumerate all four parameters including the default for read. However, the semantics are thin: "uid: Message UID" is essentially a restatement of the name and does not explain where a uid comes from (search_messages) or whether it is folder-scoped.
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 (mark a message as read or unread) and even names the underlying mechanism, the \Seen flag. It is distinguishable from the closest sibling, flag_message, only by inference from the flag name; nothing explicitly contrasts the two.
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 hints at provenance for account ("from list_accounts") and folder, which implies a discovery workflow, but there is no explicit when-to-use guidance, no exclusion versus flag_message, and no statement of prerequisites for obtaining a valid uid.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | |
| uid | Yes | |
| from | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations by disclosing the implementation: IMAP MOVE when supported, otherwise COPY plus \Deleted flag and EXPUNGE on the original. It also warns that the message receives a new UID in the destination and the old uid becomes invalid, which is critical behavioral context an agent cannot get from destructiveHint=false/true flags alone.
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 opening sentence front-loads the action, followed by the most decision-relevant behavioral caveat (UID invalidation). The Args block is slightly redundant with the schema titles but each line adds real meaning, so almost nothing is wasted.
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, non-idempotent mutation the description covers mechanism, side effects on UIDs, and parameter sourcing, and an output schema exists so return values need no explanation. Remaining gaps are failure modes such as a nonexistent dest_folder or a message that cannot be expunged, which would round it out to a 5.
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 parameter meaning, and it largely does: account is tied to list_accounts, folder is defined as the message's current folder, uid is scoped to that folder, and dest_folder points at list_folders. It does not specify the UID string format or whether dest_folder must already exist, so it falls just short of fully compensating.
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: 'Move a message from one folder to another.' That is unambiguous and clearly distinct from sibling mutations such as delete_email or flag_message. It stops short of explicitly contrasting itself with any named sibling, so it lands at 4 rather than 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 only implied: an agent infers it should call this when a message needs relocating. There is no explicit when-to-use/when-not-to-use guidance and no mention of alternatives (e.g., copy semantics or delete_email for removal). The references to list_accounts and list_folders help with prerequisites but are not usage routing.
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 |
|---|---|---|
| cc | Yes | |
| to | Yes | |
| bcc | Yes | |
| uid | Yes | |
| date | Yes | |
| from | Yes | |
| html | Yes | |
| seen | Yes | |
| text | Yes | |
| flags | Yes | |
| folder | Yes | |
| flagged | Yes | |
| subject | Yes | |
| date_iso | Yes | |
| message_id | Yes | |
| references | Yes | |
| attachments | Yes | |
| in_reply_to | Yes | |
| html_full_length | Yes | |
| text_full_length | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, and the description goes well beyond them: default body selection, 50,000-character truncation rationale (MCP result limits), the text_full_length/html_full_length size reporting, 1-based attachment part indices for save_attachment, and inclusion of threading headers. These are exactly the behaviors an agent needs to plan around and cannot get from 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 is front-loaded in the first sentence and the truncation caveat follows immediately; nothing is padded. The docstring-style 'Args:' block is slightly mechanical with wrapped lines, but given zero schema coverage that enumeration is necessary 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?
For a six-parameter read tool with an output schema, the definition covers the side-effect question, size/truncation limits, and the cross-tool linkage for attachments. Return-value detail is correctly delegated to the existing output schema, so nothing an agent needs to invoke 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 carries the full burden and does: every one of the six parameters is explained, including defaults (include_html=false, include_text=true, body_max_chars=50000), provenance of required identifiers, and the warning that HTML mail can be very large. This is meaning the schema alone does not convey.
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') and enumerates exactly what comes back: decoded headers, body, attachment list. The phrase 'without marking it read' immediately separates it from mark_read, and the mention of save_attachment/list_accounts/search_messages anchors it against siblings.
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 context is clear: it points to list_accounts, search_messages and save_attachment as the sources for its arguments, and the 'without marking it read' clause implies mark_read is the tool for that side effect. There is no explicit statement about when to prefer get_conversation over this tool for whole-thread reads, which keeps it from a 5.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | Yes | |
| to | Yes | |
| bcc | Yes | |
| from | Yes | |
| subject | Yes | |
| warning | No | |
| message_id | Yes | |
| size_bytes | Yes | |
| saved_to_folder | Yes | |
| refused_recipients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the generic profile (readOnly=false, destructive=false, openWorld=true, idempotent=false); the description adds the substantive behavior an agent needs — the reply is sent immediately and is not reversible, user confirmation is required first, and the exact addressing/threading/quoting transformations applied are spelled out.
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 imperative sentence carrying the critical safety constraint, followed by a compact behavior paragraph and a clean Args list; no filler and every clause conveys either a constraint or an observable effect.
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 7-parameter mutation tool with an output schema present, the definition covers invocation prerequisites, side effects, addressing rules, and per-parameter meaning; 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?
With 0% schema description coverage, the description carries the full burden and does document all seven parameters, adding real meaning for body (quoted original appended), reply_all (includes original To/Cc), html (alternative part), attachments (local file paths), and account (sourced from list_accounts). The folder and uid entries are largely restatements of the field names, so it falls just short of complete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ("Reply to a message and send the reply immediately") and immediately distinguishes itself from send_email/forward_email by describing reply-specific mechanics: Re: prefixing, In-Reply-To/References headers, and quoting the original body.
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 a concrete procedural constraint ("confirm with the user first") that governs when/how to invoke it, and the reply_to-an-existing-message framing implicitly excludes composing new mail. It stops short of explicitly naming send_email/forward_email as the alternatives for those cases.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| mime | Yes | |
| path | Yes | |
| size | Yes | |
| filename | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses that the mailbox is untouched, that an existing file at the target path is silently overwritten, that '~' is expanded, and that missing directories are created — all material side effects an agent could not infer from readOnlyHint/idempotentHint. The overwrite behavior is the one point of mild tension with destructiveHint=false, but because it is disclosed explicitly the agent can act on it rather than being misled.
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 definition is front-loaded with the core action and side effects, then moves into a scannable per-parameter block. Every sentence carries information — no restatement of the tool name and no filler.
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 five-required-parameter write tool, the definition covers side effects, path resolution rules, directory creation, and briefly notes the return payload (path, size, MIME type, filename) even though a full output schema exists. An agent has everything needed to call it correctly on the first attempt.
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%, yet the Args block fully documents all five parameters: 'part' is annotated as a 1-based index sourced from read_email's attachments list, and 'save_to' gets detailed disambiguation between directory mode (trailing slash, existing directory, or no extension preserves the original filename) and full-path mode. This adds meaning well beyond the bare typed properties and compensates entirely for the coverage 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?
The first sentence names a specific verb and resource ('Download one attachment from a message and write it to the local filesystem') with scope limited to a single attachment. It is clearly distinguishable from siblings like read_email (which lists attachments) and from the mail-mutation tools such as move_email or delete_email.
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 establishes the calling context by tying each input to its source: 'account from list_accounts' and 'part from read_email's attachments list', which tells an agent the prerequisite read step. It also states 'The mailbox is not modified', implying this is not a substitute for move/delete operations. It stops short of explicit when-not-to-use or naming an alternative save mechanism, so it falls short of a 5.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | Yes | |
| to | Yes | |
| bcc | Yes | |
| from | Yes | |
| subject | Yes | |
| message_id | Yes | |
| size_bytes | Yes | |
| saved_to_folder | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which already declare readOnlyHint=false, destructiveHint=false, idempotentHint=false), the description discloses the actual mechanism: appended to the special-use Drafts folder with the \Draft flag, and 'Each call creates a new draft', which reinforces non-idempotency concretely. It does not mention failure modes such as invalid account or missing attachment paths.
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 the send_email contrast before the Args block, and no filler sentences. The Args block is somewhat verbose at 10 lines but each maps to a distinct parameter.
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-parameter mutation whose return values are already covered by an output schema, the description supplies folder/flag semantics, threading guidance for in_reply_to and references, and per-parameter meaning. Nothing an agent needs to construct a correct call 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 param burden; its Args block documents all 10 parameters and adds real meaning where the schema has only titles — 'Message-ID this draft replies to, for threading', 'Message-IDs of earlier messages in the thread', 'Local file paths to attach', and the cross-reference 'Account name from list_accounts'. A few entries (subject, body) are near-restatements, keeping it short of 5.
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 the specific verb+resource ('Compose an email and save it to the account's Drafts folder without sending it') and immediately contrasts with send_email, so an agent can separate it from the closest sibling 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?
Explicitly says 'Use this instead of send_email whenever the user wants to check a message first', which is a clear when-to-use rule with a named alternative. It does not address when to prefer reply_email/forward_email versus using in_reply_to/references here, leaving one sibling relationship to inference.
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?
Beyond the annotations (readOnly, idempotent, non-destructive), it discloses the key operational behavior: the folder is opened read-only so searching never marks mail read — a real risk with IMAP SEARCH. It also explains filter composition (all AND), string matching semantics (case-insensitive substring, auto-quoting of multi-word values), ordering (newest first), and that has_attachment is best-effort rather than exact.
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 summary sentence is front-loaded and the Args block is scannable, which is appropriate for 16 parameters. A few lines are near-redundant with the parameter names (cc, to, subject), but the overall size is justified by the parameter count.
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 the result-field enumeration is belt-and-braces but useful for deciding whether a follow-up read_email is needed. The definition covers all filters, matching semantics, and read-only safety for a 16-parameter tool; the only remaining gap is pagination/truncation semantics for limit and any error behavior for invalid folders or malformed raw queries.
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 16 parameters, and it does document each one with defaults and meaning, plus value-format details the schema omits (YYYY-MM-DD for since/before, raw IMAP syntax example, quoting behavior). It does not clarify whether seen/unseen are mutually exclusive or how they interact, and limit has no note about truncation behavior.
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 opening sentence gives a specific verb (search), a scoped resource (one folder), the mechanism (structured filters), and the return shape (message envelopes, newest first). The single-folder scope plus the redirect to read_email for bodies clearly separates it from siblings like read_email and get_conversation.
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 routes explicitly: use list_accounts for the account name, list_folders or resolve_folder for other folders, and pass folder + uid to read_email when the body is needed. It also states that setting raw disables every other filter, which prevents misuse. It lacks explicit guidance on when to prefer this over get_conversation for thread-shaped questions.
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 |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | Yes | |
| to | Yes | |
| bcc | Yes | |
| from | Yes | |
| subject | Yes | |
| warning | No | |
| message_id | Yes | |
| size_bytes | Yes | |
| saved_to_folder | Yes | |
| refused_recipients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations it discloses the irreversible nature of the action, the conditional Sent-folder side effect tied to auto_save_sent (with the iCloud rationale), and the contents of the return value including the null case. That is meaningful context the annotations do not convey. It does not cover failure modes such as SMTP errors or attachment limits, so it stops short of the top mark.
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 irreversible-action warning and the sibling routing are front-loaded before the mechanical Args list, which is the right ordering for a high-stakes tool. The Args block is long but each line is short and scannable; only the subject/body entries are wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, non-idempotent, open-world mutation tool, the description covers prerequisites, the confirmation requirement, the side effect on the Sent folder, and the alternative tool for replies. Return values are summarized even though an output schema exists, and nothing essential to calling 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 parameter meaning, and the Args block largely does: it explains where account values come from, that bcc addresses are never written to headers, that attachments are local file paths, and that in_reply_to/references drive threading. A few entries are near-tautological restatements ("subject: Subject line", "body: Plain-text body"), which keeps it from a 5.
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 opening clause names a specific verb and resource ("Send a new email over SMTP") plus an immediacy constraint, and the closing sentence explicitly separates it from reply_email, which covers the respond-to-existing-message case. An agent can distinguish this from save_draft_email, reply_email, and forward_email without inspecting 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?
It gives both a positive usage rule and an explicit alternative: "To answer an existing message prefer reply_email, which fills in recipients and threading for you." It also states a prerequisite (account name comes from list_accounts) and a required pre-action step (confirm with the user first).
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.
14 tool updates
v0.3.0- Changed
delete_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "from": { + "title": "From", + "type": "string" + }, + "to": { + "title": "To", + "type": "string" + }, + "uid": { + "title": "Uid", + "type": "string" + } + }, + "required": [ + "uid", + "from", + "to" + ], + "title": "MoveResult", + "type": "object" +}
- Changed
flag_message1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "flagged": { + "title": "Flagged", + "type": "boolean" + }, + "folder": { + "title": "Folder", + "type": "string" + }, + "uid": { + "title": "Uid", + "type": "string" + } + }, + "required": [ + "uid", + "folder", + "flagged" + ], + "title": "FlagState", + "type": "object" +}
- Changed
forward_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "bcc": { + "items": { + "type": "string" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "type": "string" + }, + "title": "Cc", + "type": "array" + }, + "from": { + "title": "From", + "type": "string" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "refused_recipients": { + "items": { + "type": "string" + }, + "title": "Refused Recipients", + "type": "array" + }, + "saved_to_folder": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Saved To Folder" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "type": "string" + }, + "title": "To", + "type": "array" + }, + "warning": { + "title": "Warning", + "type": "string" + } + }, + "required": [ + "message_id", + "from", + "to", + "cc", + "bcc", + "subject", + "saved_to_folder", + "size_bytes", + "refused_recipients" + ], + "title": "SendResult", + "type": "object" +}
- Changed
get_conversation4 fields changed- added
Output schema / $defsAdded value: +{ + "Address": { + "properties": { + "email": { + "title": "Email", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + } + }, + "required": [ + "name", + "email" + ], + "title": "Address", + "type": "object" + }, + "Envelope": { + "properties": { + "bcc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Cc", + "type": "array" + }, + "date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date" + }, + "date_iso": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date Iso" + }, + "flagged": { + "title": "Flagged", + "type": "boolean" + }, + "flags": { + "items": { + "type": "string" + }, + "title": "Flags", + "type": "array" + }, + "folder": { + "title": "Folder", + "type": "string" + }, + "from": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "From", + "type": "array" + }, + "in_reply_to": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "In Reply To" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "title": "References", + "type": "array" + }, + "seen": { + "title": "Seen", + "type": "boolean" + }, + "size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Size" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "To", + "type": "array" + }, + "uid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Uid" + } + }, + "required": [ + "uid", + "folder", + "message_id", + "in_reply_to", + "references", + "subject", + "from", + "to", + "cc", + "bcc", + "date", + "date_iso", + "flags", + "seen", + "flagged", + "size" + ], + "title": "Envelope", + "type": "object" + } +} - added
Output schema / properties / result / items / $refAdded value: +"#/$defs/Envelope" - removed
Output schema / properties / result / items / additionalPropertiesRemoved value: -true - removed
Output schema / properties / result / items / typeRemoved value: -"object"
- Changed
list_accounts4 fields changed- added
Output schema / $defsAdded value: +{ + "AccountInfo": { + "properties": { + "auto_save_sent": { + "title": "Auto Save Sent", + "type": "boolean" + }, + "email": { + "title": "Email", + "type": "string" + }, + "imap_host": { + "title": "Imap Host", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + }, + "smtp_host": { + "title": "Smtp Host", + "type": "string" + } + }, + "required": [ + "name", + "email", + "provider", + "imap_host", + "smtp_host", + "auto_save_sent" + ], + "title": "AccountInfo", + "type": "object" + } +} - added
Output schema / properties / result / items / $refAdded value: +"#/$defs/AccountInfo" - removed
Output schema / properties / result / items / additionalPropertiesRemoved value: -true - removed
Output schema / properties / result / items / typeRemoved value: -"object"
- Changed
list_folders4 fields changed- added
Output schema / $defsAdded value: +{ + "Folder": { + "properties": { + "delimiter": { + "title": "Delimiter", + "type": "string" + }, + "flags": { + "title": "Flags", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "role": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Role" + } + }, + "required": [ + "name", + "flags", + "delimiter", + "role" + ], + "title": "Folder", + "type": "object" + } +} - added
Output schema / properties / result / items / $refAdded value: +"#/$defs/Folder" - removed
Output schema / properties / result / items / additionalPropertiesRemoved value: -true - removed
Output schema / properties / result / items / typeRemoved value: -"object"
- Changed
mark_read1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "folder": { + "title": "Folder", + "type": "string" + }, + "seen": { + "title": "Seen", + "type": "boolean" + }, + "uid": { + "title": "Uid", + "type": "string" + } + }, + "required": [ + "uid", + "folder", + "seen" + ], + "title": "ReadState", + "type": "object" +}
- Changed
move_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "from": { + "title": "From", + "type": "string" + }, + "to": { + "title": "To", + "type": "string" + }, + "uid": { + "title": "Uid", + "type": "string" + } + }, + "required": [ + "uid", + "from", + "to" + ], + "title": "MoveResult", + "type": "object" +}
- Changed
read_email5 fields changed- added
Output schema / $defsAdded value: +{ + "Address": { + "properties": { + "email": { + "title": "Email", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + } + }, + "required": [ + "name", + "email" + ], + "title": "Address", + "type": "object" + }, + "Attachment": { + "properties": { + "content_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Content Id" + }, + "filename": { + "title": "Filename", + "type": "string" + }, + "mime": { + "title": "Mime", + "type": "string" + }, + "part": { + "title": "Part", + "type": "integer" + }, + "size": { + "title": "Size", + "type": "integer" + } + }, + "required": [ + "part", + "filename", + "mime", + "size", + "content_id" + ], + "title": "Attachment", + "type": "object" + } +} - removed
Output schema / additionalPropertiesRemoved value: -true - added
Output schema / propertiesAdded value: +{ + "attachments": { + "items": { + "$ref": "#/$defs/Attachment" + }, + "title": "Attachments", + "type": "array" + }, + "bcc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Cc", + "type": "array" + }, + "date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date" + }, + "date_iso": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date Iso" + }, + "flagged": { + "title": "Flagged", + "type": "boolean" + }, + "flags": { + "items": { + "type": "string" + }, + "title": "Flags", + "type": "array" + }, + "folder": { + "title": "Folder", + "type": "string" + }, + "from": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "From", + "type": "array" + }, + "html": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Html" + }, + "html_full_length": { + "title": "Html Full Length", + "type": "integer" + }, + "in_reply_to": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "In Reply To" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "title": "References", + "type": "array" + }, + "seen": { + "title": "Seen", + "type": "boolean" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Text" + }, + "text_full_length": { + "title": "Text Full Length", + "type": "integer" + }, + "to": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "To", + "type": "array" + }, + "uid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Uid" + } +} - added
Output schema / requiredAdded value: +[ + "uid", + "folder", + "message_id", + "in_reply_to", + "references", + "subject", + "from", + "to", + "cc", + "bcc", + "date", + "date_iso", + "flags", + "seen", + "flagged", + "text", + "html", + "text_full_length", + "html_full_length", + "attachments" +] - changed
Output schema / titlePrevious value: -"read_emailDictOutput"New value: +"Message"
- Changed
reply_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "bcc": { + "items": { + "type": "string" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "type": "string" + }, + "title": "Cc", + "type": "array" + }, + "from": { + "title": "From", + "type": "string" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "refused_recipients": { + "items": { + "type": "string" + }, + "title": "Refused Recipients", + "type": "array" + }, + "saved_to_folder": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Saved To Folder" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "type": "string" + }, + "title": "To", + "type": "array" + }, + "warning": { + "title": "Warning", + "type": "string" + } + }, + "required": [ + "message_id", + "from", + "to", + "cc", + "bcc", + "subject", + "saved_to_folder", + "size_bytes", + "refused_recipients" + ], + "title": "SendResult", + "type": "object" +}
- Changed
save_attachment1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "filename": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Filename" + }, + "mime": { + "title": "Mime", + "type": "string" + }, + "path": { + "title": "Path", + "type": "string" + }, + "size": { + "title": "Size", + "type": "integer" + } + }, + "required": [ + "path", + "size", + "mime", + "filename" + ], + "title": "SavedAttachment", + "type": "object" +}
- Changed
save_draft_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "bcc": { + "items": { + "type": "string" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "type": "string" + }, + "title": "Cc", + "type": "array" + }, + "from": { + "title": "From", + "type": "string" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "saved_to_folder": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Saved To Folder" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "type": "string" + }, + "title": "To", + "type": "array" + } + }, + "required": [ + "message_id", + "from", + "to", + "cc", + "bcc", + "subject", + "saved_to_folder", + "size_bytes" + ], + "title": "DraftResult", + "type": "object" +}
- Changed
search_messages4 fields changed- added
Output schema / $defsAdded value: +{ + "Address": { + "properties": { + "email": { + "title": "Email", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + } + }, + "required": [ + "name", + "email" + ], + "title": "Address", + "type": "object" + }, + "Envelope": { + "properties": { + "bcc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "Cc", + "type": "array" + }, + "date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date" + }, + "date_iso": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Date Iso" + }, + "flagged": { + "title": "Flagged", + "type": "boolean" + }, + "flags": { + "items": { + "type": "string" + }, + "title": "Flags", + "type": "array" + }, + "folder": { + "title": "Folder", + "type": "string" + }, + "from": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "From", + "type": "array" + }, + "in_reply_to": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "In Reply To" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "title": "References", + "type": "array" + }, + "seen": { + "title": "Seen", + "type": "boolean" + }, + "size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Size" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "$ref": "#/$defs/Address" + }, + "title": "To", + "type": "array" + }, + "uid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Uid" + } + }, + "required": [ + "uid", + "folder", + "message_id", + "in_reply_to", + "references", + "subject", + "from", + "to", + "cc", + "bcc", + "date", + "date_iso", + "flags", + "seen", + "flagged", + "size" + ], + "title": "Envelope", + "type": "object" + } +} - added
Output schema / properties / result / items / $refAdded value: +"#/$defs/Envelope" - removed
Output schema / properties / result / items / additionalPropertiesRemoved value: -true - removed
Output schema / properties / result / items / typeRemoved value: -"object"
- Changed
send_email1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "bcc": { + "items": { + "type": "string" + }, + "title": "Bcc", + "type": "array" + }, + "cc": { + "items": { + "type": "string" + }, + "title": "Cc", + "type": "array" + }, + "from": { + "title": "From", + "type": "string" + }, + "message_id": { + "title": "Message Id", + "type": "string" + }, + "refused_recipients": { + "items": { + "type": "string" + }, + "title": "Refused Recipients", + "type": "array" + }, + "saved_to_folder": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Saved To Folder" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "subject": { + "title": "Subject", + "type": "string" + }, + "to": { + "items": { + "type": "string" + }, + "title": "To", + "type": "array" + }, + "warning": { + "title": "Warning", + "type": "string" + } + }, + "required": [ + "message_id", + "from", + "to", + "cc", + "bcc", + "subject", + "saved_to_folder", + "size_bytes", + "refused_recipients" + ], + "title": "SendResult", + "type": "object" +}
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 distinct email action or resource: account/folder discovery, search, read, attachment save, thread retrieval, send/draft/reply/forward, flagging, moving, deleting, and role resolution. Overlaps such as search_messages vs get_conversation and send_email vs reply_email are clearly differentiated by their descriptions.
All tool names use consistent snake_case with a verb_noun pattern: list_accounts, search_messages, read_email, send_email, move_email, delete_email, etc. Minor variants like save_draft_email still follow the same convention.
15 tools is at the upper end of the ideal range but every tool serves a clear purpose in the email workflow. The set covers discovery, search, reading, sending, replying, forwarding, drafting, flagging, moving, and deleting without obvious redundancy.
Core email lifecycle coverage is strong: accounts, folders, search, read, attachments, conversation threading, compose/send/reply/forward/draft, flags, move, and delete. Minor gaps remain around folder creation/deletion and editing or deleting drafts, but agents can largely work around these.
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.823 PyPIMIT
- AlicenseNot gradedqualityBmaintenanceA unified MCP server for email access across Gmail, Outlook, iCloud, and generic IMAP providers, enabling search, send, organize, and batch operations.785 npm26MIT
- AlicenseBqualityCmaintenanceUniversal IMAP/SMTP MCP server that works with any email provider, providing tools to read, search, send, and manage emails.10242 npm1MIT