protonmail-mcp
Provides read-only access to a Proton Mail mailbox through a local Proton Bridge instance, with tools to list folders and labels, list recent messages (filtered by unread status, date range, sender, or subject), perform full-text search across headers and body, and read individual messages by Message-ID with decoded text body, attachments, and flags. When the optional draft capability is enabled, it also supports listing, creating, previewing, and two-phase (prepare/commit) management of drafts, including replying, forwarding, updating, and deleting.
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., "@protonmail-mcpshow my unread emails from the last 3 days"
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.
protonmail-mcp
A lightweight MCP server that gives AI agents read access to a Proton Mail mailbox through a local Proton Bridge instance.
Unofficial. This project is not affiliated with, endorsed by, or supported by Proton AG. "Proton Mail" and "Proton Bridge" are trademarks of Proton AG.
Proton does not provide a public API for reading your mailbox. Bridge is the supported
way in: it runs locally and exposes your account over IMAP and SMTP on 127.0.0.1.
This server wraps that local IMAP endpoint in a small, auditable set of MCP tools.
Scope
Capabilities are opt-in through policy (see Capability policy) and enforced server-side:
read (default): folders, messages, search, threads, digests, attachments and
.emlexport into a local sandbox. Mailboxes are opened with IMAPSELECT ... READONLY; nothing is modified, not even the\Seenflag.draft: create, preview, reply/forward, update and delete drafts, all two-phase.
organize: seen/flagged state, moves with undo, label add/remove.
send: submit an existing draft through Bridge SMTP after allowlist, quota, size and loop-guard checks.
delete: permanently erase one message from Trash, with a typed confirmation phrase and no bulk operation.
Every mutation is prepare/commit with payload-bound confirmation tokens; see SECURITY.md for the security model.
Related MCP server: proton-mcp-server
Tools
Tool | Description |
| List every folder and label, with IMAP flags and whether it is selectable |
| Total and unread counts per folder, without fetching messages |
| Most recent messages in a folder, newest first, with a pagination cursor: |
| Structured search: |
| Read one message by |
| Reconstruct a conversation across All Mail using References/In-Reply-To |
| Unread count plus compact recent-message summaries for a folder |
| Attachment names, types and sizes without saving anything |
| Save one attachment into the local sandbox (traversal-safe, size-capped, never overwrites) |
| Export a message as |
| Index recent messages into the local SQLite FTS5 store (opt-in via |
| Fast, offline full-text search over the local index |
When the draft capability is enabled (see Capability policy),
additional tools are registered: list_drafts, create_draft, preview_draft (renders
the exact MIME without saving it), and prepare_*/commit_* pairs for replying,
forwarding, updating, and deleting drafts. Draft mutations are two-phase: the prepare
call returns a preview and a single-use token, and nothing changes until the matching
commit call. Draft attachments always come from the local sandbox (files.directory);
prepare_forward_draft/commit_forward_draft can additionally re-attach the original
message's attachments with include_attachments=true, subject to the message size cap. Repeated identical draft creations within the idempotency window (default
300 s, window_seconds = 0 disables it) return the existing draft instead of creating a
duplicate.
When the organize capability is enabled, another set of prepare/commit tools is
registered: seen/flagged state (prepare_set_flags), moves (destination accepts a folder
name or the aliases archive and trash), label add/remove for folders under Labels/,
and prepare_undo_move to revert the most recent move. Bulk operations are capped
(organize.max_bulk, default 50), Drafts are protected by default, travel to Starred must
go through flag/unflag, and every mutation is previewed before its commit.
When the send capability is enabled, prepare_send_draft / commit_send_draft submit
an existing draft through Bridge SMTP. Before anything is transmitted the server checks
the recipient allowlist, hourly/daily quotas, message size, and loop guards
(Auto-Submitted, Precedence, List-*, no-reply recipients, thread depth, duplicate
bodies). The draft is removed only after the SMTP server accepts the message. See
docs/send-design.md.
When the delete capability is enabled, prepare_delete_message /
commit_delete_message permanently erase a single message from Trash. The commit must
repeat the exact phrase permanently delete <message-id>; there is no bulk deletion and
no empty-trash tool.
When [index] enabled = true, sync_index builds a local plaintext SQLite FTS5 store
(headers plus truncated body text; attachments are never indexed and folders can be
excluded) and search_index queries it for fast offline search.
MCP resources
The server also exposes read-only resources: mail://folders, mail://status, and the
templates mail://message/{message-id} and mail://thread/{message-id} (percent-encode
Message-IDs, for example %3Cid%40example.com%3E). They contain the same data as the read
tools and never trigger writes.
With [notifications] enabled = true, the server watches notifications.folder with
IMAP IDLE and publishes resource-updated events for mail://inbox (clients subscribe via
resources/subscribe, or subscriptions/listen on newer protocol versions). Events
carry no content; the mail://inbox resource itself exposes only counts and recent
message identifiers. The watcher reconnects with exponential backoff and logs to stderr.
Timeliness follows Bridge's own sync with Proton: local mailbox changes are noticed within
about a second, while server-side arrivals can lag by tens of seconds or more.
Results are structured (Pydantic models). Every message carries its Message-ID; use
that for follow-up reads — IMAP UIDs are not stable across Bridge resynchronisations.
Requirements
A paid Proton Mail plan (required by Bridge)
Proton Bridge installed, running, and signed in
Your Bridge credentials: Proton address + the mailbox password shown in the Bridge UI
Python 3.13+ (only if you do not use
uv)
Install
# Run without installing (recommended)
uvx protonmail-mcp
# Force uvx to pick up the newest release if an older one is cached
uvx --refresh protonmail-mcp
# Or install it
pipx install protonmail-mcpConfigure
Variable | Default | Purpose |
| — | Your Proton address (required) |
| — | Bridge mailbox password (required) |
|
| Bridge host |
|
| Bridge IMAP port |
|
|
|
|
| Socket timeout in seconds |
|
| Bridge uses a self-signed certificate |
|
| Capability preset: |
|
| Optional policy file with capability overrides and limits |
Capability policy
Write capabilities are opt-in and enforced server-side. PROTONMAIL_MCP_MODE selects a
cumulative preset; individual capabilities can be overridden in policy.toml (see
policy.example.toml). Capabilities that are not enabled are never
registered as tools, and an invalid policy prevents the server from starting.
[policy]
mode = "read"
[capabilities]
# draft = true
# organize = true
# send = true
# delete = true
[confirmations]
ttl_seconds = 300
[idempotency]
window_seconds = 300
[organize]
max_bulk = 50
protect_drafts = true
# allowed_targets = ["Archive", "Folders/Newsletters"]
# label_allowlist = ["Labels/Important"]
[files]
directory = "~/.local/share/protonmail-mcp/files"
max_bytes = 26214400
[send]
allow_self = true
max_per_hour = 20
max_per_day = 100
state_path = "~/.local/state/protonmail-mcp/state.db"
[index]
enabled = false
path = "~/.local/state/protonmail-mcp/index.db"
# excluded_folders = ["Spam"]
max_body_chars = 10000
[notifications]
enabled = false
folder = "INBOX"
min_interval_seconds = 30See SECURITY.md for the confirmation flow and ROADMAP.md for what each mode will unlock.
opencode
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"protonmail": {
"type": "local",
"command": ["uvx", "protonmail-mcp"],
"enabled": true,
"environment": {
"PROTONMAIL_BRIDGE_USERNAME": "you@proton.me",
"PROTONMAIL_BRIDGE_PASSWORD": "your-bridge-mailbox-password"
}
}
}
}opencode supports {env:VAR} and {file:path} interpolation, so you can keep secrets
out of the config file:
"PROTONMAIL_BRIDGE_PASSWORD": "{file:/home/you/.config/protonmail-mcp/password}"Claude Desktop
{
"mcpServers": {
"protonmail": {
"command": "uvx",
"args": ["protonmail-mcp"],
"env": {
"PROTONMAIL_BRIDGE_USERNAME": "you@proton.me",
"PROTONMAIL_BRIDGE_PASSWORD": "your-bridge-mailbox-password"
}
}
}
}Verify the connection
PROTONMAIL_BRIDGE_USERNAME="you@proton.me" \
PROTONMAIL_BRIDGE_PASSWORD="..." \
uvx protonmail-mcp --checkThis connects to Bridge, lists folders, and prints the latest messages. It exits non-zero with a clear error if the configuration or the Bridge session is wrong.
Remote HTTP transport (optional)
By default the server speaks stdio. To serve MCP over streamable HTTP instead:
export PROTONMAIL_MCP_HTTP_TOKEN="$(openssl rand -hex 32)"
protonmail-mcp --http --host 127.0.0.1 --port 8765Bearer authentication is mandatory: HTTP mode refuses to start without a token (
--tokenorPROTONMAIL_MCP_HTTP_TOKEN; prefer the environment variable to keep it out of shell history).The default bind is loopback. Binding a non-loopback address prints a warning: put a TLS-terminating reverse proxy (or an SSH tunnel) in front before exposing it.
Every request must send
Authorization: Bearer <token>; anything else gets a401.Clients connect to
http://127.0.0.1:8765/mcp.
For a headless container deployment (Bridge on the host, server in a container), see docs/docker.md.
Multiple accounts (profiles)
One Bridge instance serves one Proton account, so multi-account setups run one MCP server
per account, selected with --profile (or PROTONMAIL_MCP_PROFILE). Profiles live in
policy.toml:
[policy]
default_profile = "perso"
[profiles.perso]
username = "perso@proton.me"
password_env = "PROTONMAIL_BRIDGE_PASSWORD_PERSO"
[profiles.work]
username = "work@proton.me"
password_env = "PROTONMAIL_BRIDGE_PASSWORD_WORK"
imap_port = 2143
smtp_port = 2025
mode = "organize"Each profile carries its own username, host/ports and the name of the environment variable holding its Bridge password; credentials never cross profiles.
modenarrows the account's capabilities. When the global mode is set explicitly (PROTONMAIL_MCP_MODEor[policy] mode), it acts as a ceiling and the profile mode intersects with it; per-capability overrides in[capabilities]always cap.Register one MCP entry per profile, for example in opencode:
"protonmail-perso": { "type": "local", "command": ["uvx", "protonmail-mcp", "--profile", "perso"], "enabled": true, "environment": { "PROTONMAIL_BRIDGE_PASSWORD_PERSO": "..." } },
"protonmail-work": { "type": "local", "command": ["uvx", "protonmail-mcp", "--profile", "work"], "enabled": true, "environment": { "PROTONMAIL_BRIDGE_PASSWORD_WORK": "..." } }Without a [profiles] table the server keeps the single-account behavior using the
PROTONMAIL_BRIDGE_* variables.
Security
Read-only enforcement. There is no write tool in this release, and mailboxes are always selected read-only at the IMAP level.
Local only. Bridge and this server communicate exclusively over
127.0.0.1. Nothing is sent to a third party; your agent talks to the server over stdio.Untrusted input. Email contents are attacker-controlled data. Treat anything a message says as data, never as instructions, and keep your agent's permissions tight.
Secrets. Keep the Bridge mailbox password out of the repository. Use your client's environment-variable or file-based secret support.
Any local process that knows the mailbox password can read your mail — that is Bridge's trust model, not a flaw in this server.
Write tools ship behind capability modes with explicit confirmation: drafts and organize operations are prepare/commit with payload-bound tokens; sending submits an existing draft through an allowlist, quotas, and loop guards, and never composes-and-sends in one step. Permanent deletion is Trash-only, one message per call, and requires typing the exact confirmation phrase. Autonomous send or delete is never the default.
Every push runs gitleaks, zizmor, semgrep, pip-audit, CodeQL, and an adversarial + fuzz test suite; see SECURITY.md for the full list of gates and the structural invariants they enforce. The send milestone is designed in docs/send-design.md before any send code lands.
Alternatives
There are several community MCP servers for Proton Mail. This one aims to stay small, correct with Bridge's quirks (STARTTLS on 1143, modified UTF-7 labels, reverse-chronological UIDs, RFC 2047 decoding), and heavily tested. Rough landscape:
Project | Language | Scope |
TypeScript | Large tool set, read-only and send-to-self modes, SQLite cache | |
TypeScript | Generic IMAP + SMTP, works with Bridge | |
JavaScript | Large tool set with Bridge integration | |
TypeScript | Large permission-gated tool set | |
JavaScript | SMTP sending only | |
Python | Loopback IMAP/SMTP via Bridge |
Development
uv sync
uv run pytest
uv run ruff check .
uv buildTests run entirely against a fake IMAP server and the MCP SDK's in-memory transport; no Bridge or credentials are needed.
Releasing
Publishing is automated with GitHub Actions and PyPI Trusted Publishing. Create a
GitHub release tagged vX.Y.Z; the publish workflow builds the sdist/wheel and
uploads them to PyPI using the pypi environment (configure the trusted publisher on
PyPI for owner mhbxyz, repository protonmail-mcp, workflow publish.yml).
License
MIT — see LICENSE.
Available Tools
10 toolsdaily_digestARead-only
Compact digest of a folder: unread count plus recent message summaries (subjects and senders only, no bodies).
Args: folder: Folder to summarize. days: Window in days (default 1). limit: Maximum messages in the digest (1-100).
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | ||
| limit | No | ||
| folder | No | INBOX |
Output Schema
| Name | Required | Description |
|---|---|---|
| folder | Yes | |
| unread | Yes | |
| messages | No | |
| since_days | Yes | |
| total_recent | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes the safe-read profile, and the description adds real behavioral context beyond it: what is included (unread count, summaries), what is deliberately excluded (bodies), and the bounded result size. Missing only notes on truncation/pagination behavior at the limit ceiling.
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?
One front-loaded sentence gives the whole contract, followed by a tight Args block that is justified given the zero schema coverage. Slight redundancy in restating the schema's default values, but no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and readOnlyHint covers safety. The description supplies purpose, content scope, and all three parameters, leaving only minor gaps such as how the unread count is derived or behavior at the limit boundary.
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 parameter burden and does document all three: folder as target, days as the window, limit as the digest size. It also supplies the 1-100 range that is absent from the schema, though the stated defaults merely duplicate schema values.
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 (digest of a folder) and pins down the exact payload: unread count plus recent message summaries with subjects and senders only, no bodies. This implicitly separates it from read_email/list_emails, but no sibling is named explicitly, so it stops 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?
The 'compact digest' framing implies the right moment (a quick overview rather than fetching full messages), but the description never states when to prefer this over list_emails or search_emails, nor any exclusions. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_emailA
Export a full message as .eml into the local sandbox directory.
Args: message_id: Message-ID of the message. folder: Folder containing the message. filename: Optional target filename; defaults to the Message-ID plus .eml.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No | INBOX | |
| filename | No | ||
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| filename | Yes | |
| size_bytes | Yes | |
| content_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=false, destructiveHint=false, so the agent knows this writes a file but is non-destructive. The description adds genuinely useful context (the file lands in the local sandbox directory, and the filename defaults), but it never explains the non-idempotent behavior, e.g. what happens if the target file already exists or whether an existing file is overwritten.
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 single lead sentence is front-loaded with purpose, format, and destination, followed by a compact Args list for the three parameters. No filler or repetition; only the arg restatement of types is mildly redundant.
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 no explanation, and the description covers purpose, destination, and all three parameters. The remaining gap is overwrite/collision behavior for a non-idempotent write, which is a minor omission for this tool's complexity.
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 largely does: it defines message_id as the Message-ID, folder as the containing folder, and filename as optional with a stated default (Message-ID plus .eml) that goes beyond the schema's bare default of null. The folder default of INBOX is left to the schema, so it is not fully exhaustive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (export), resource (a full message), output format (.eml), and destination (the local sandbox directory), which clearly separates it from read_email and save_attachment. It does not explicitly name a sibling or contrast itself with them, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is for materializing a raw .eml file locally rather than reading content in-context. There is no explicit when-to-use statement, no condition for choosing it over read_email or save_attachment, and no exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statusARead-only
Counts of total and unread messages per folder, without fetching messages.
Args: folder: A single folder name, or omit to get every selectable folder.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already declares this as a safe read, so the description only needs to add context beyond that. 'Without fetching messages' usefully signals a lightweight operation that avoids downloading bodies, but there is no mention of performance, caching, or failure modes for a non-selectable folder.
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?
One front-loaded sentence plus a single tight Args line; no filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, and the description covers the one parameter's behavior. It is nearly complete for this simple tool, only lacking explicit routing to sibling tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the burden for the single folder parameter and does so clearly: a single folder name, or omit for all selectable folders. This adds real semantics (singular name, null means 'every selectable folder') that the bare string/null schema 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 ('counts of total and unread messages per folder') and adds the scoping qualifier 'without fetching messages', which implicitly separates it from list_emails/read_email. It does not name a sibling explicitly, so it falls just short of 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?
The Args note tells the agent that omitting the folder returns every selectable folder, which implies efficient bulk use. However, there is no explicit when-to-use-this-vs-alternatives guidance (e.g. use this instead of list_emails to get counts cheaply).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_threadARead-only
Reconstruct a conversation around a message using References/In-Reply-To, searching All Mail. Returns messages in chronological order.
Args: message_id: Message-ID of any message in the thread. folder: Folder containing that message (used as a fallback if All Mail is absent). limit: Maximum messages in the thread (1-100).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| folder | No | INBOX | |
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation only covers safety. The description adds rich behavioral context: the thread-reconstruction strategy, All Mail search scope, fallback to the containing folder, chronological ordering, and the 1-100 limit range.
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 list is compact and directly useful. Every sentence adds operational detail without 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?
An output schema exists, so return values need not be explained. With annotations covering read-only safety and the description covering search scope, fallback, ordering, and parameter constraints, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate fully. It documents all three parameters: message_id as any message in the thread, folder as a fallback if All Mail is absent, and limit as a 1-100 maximum.
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: reconstructs a conversation/thread around a message. It also names the mechanism (References/In-Reply-To) and search scope (All Mail), making it distinguishable from siblings like read_email and search_emails.
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?
Clear context: call it with a message_id from any message in the thread to retrieve the full conversation. It does not explicitly name the sibling alternatives or state when-not-to-use conditions, so it falls short of full explicit guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_attachmentsARead-only
List a message's attachments (names, content types, sizes) without saving anything to disk.
Args: message_id: Message-ID of the message. folder: Folder containing the message.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No | INBOX | |
| message_id | 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=true, and the description reinforces this with 'without saving anything to disk', plus discloses what the result contains (attachment names, content types, sizes). It adds useful behavioural context beyond the annotation, though it says nothing about permissions or failure modes.
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 purpose and the no-disk-write constraint are front-loaded in one efficient sentence; the trailing Args block is mildly redundant formatting but adds no padding. Nothing 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?
With an output schema present, return values need not be described, yet the description helpfully indicates the metadata fields. Both parameters and the read-only nature are covered; only auth requirements and error behaviour are absent, which is acceptable for this simple listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the parameter burden — and it does, defining message_id as the Message-ID and folder as the folder containing the message. The only gap is that the INBOX default is left to the schema rather than restated.
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 (List) and resource (a message's attachments) and immediately scopes the output to metadata — names, content types, sizes — which cleanly separates it from save_attachment in the sibling set.
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 phrase 'without saving anything to disk' signals the read-only context and implicitly contrasts with save_attachment, giving clear usage context. However, it never names the alternative tool or states an explicit when-to-use condition, so it stops 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.
list_emailsARead-only
List the most recent messages of a folder, newest first.
Args: folder: Folder or label name, as returned by list_folders. limit: Maximum number of messages to return (1-100). unread_only: Only return unread messages when true. since_days: Only return messages from the last N days when set. sender: Only return messages whose From header contains this text. subject: Only return messages whose Subject header contains this text. before: Cursor from a previous page's next_cursor to continue listing.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| before | No | ||
| folder | No | INBOX | |
| sender | No | ||
| subject | No | ||
| since_days | No | ||
| unread_only | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| folder | Yes | |
| messages | No | |
| next_cursor | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint=true annotation already establishes the safety profile, so the bar is lower. The description does add real behavioral value beyond annotations: newest-first ordering and, importantly, the cursor contract ('Cursor from a previous page's next_cursor to continue listing'), which reveals pagination. It still says nothing about how multiple filters combine or result caps.
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 before the Args block, and each argument line earns its place given zero schema coverage. The docstring-style enumeration is slightly formulaic but contains 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?
An output schema exists, so return values need not be described, and the readOnly annotation covers safety. The description adds ordering and pagination, the two things structured fields do not cover. Minor gaps: the default folder of INBOX and whether filters are AND-combined are not stated.
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 so: every one of the seven parameters gets a meaning, including match semantics ('From header contains this text'), the 1-100 bound on limit (absent from the schema), and the next_cursor round-trip for 'before'. This is substantially more than the schema names provide.
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 most recent messages of a folder') plus the sort order ('newest first'), which lets an agent distinguish it from a single-message reader like read_email. It does not, however, differentiate itself from search_emails, which is the closest sibling and the one an agent is most likely to confuse it with.
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: the tool is for enumerating a folder's contents with optional narrowing filters. The one sibling reference ('as returned by list_folders') is a data dependency for the folder argument, not guidance on when to pick this tool over search_emails or get_thread, and no exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_foldersARead-only
List every folder and label of the mailbox. Use this first when you do not know where a message lives; the returned names are valid values for other tools.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes this as a safe, non-mutating read. The description adds real value beyond that by disclosing that the output is a discovery artifact feeding other tools, but it says nothing about mailbox breadth, permissions, or large-mailbox behavior.
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?
Two sentences, both load-bearing: the first states the action, the second states when to call it and why the result matters. The primary guidance is front-loaded with 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?
With an output schema present, the description need not document the returned folder structure, and it correctly focuses on when to call the tool and how to consume its output. It is nearly complete; only the call-ordering relationship with sibling tools could be tightened further.
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, so there are no argument semantics to explain; the baseline for a parameterless tool applies. Nothing in the description conflicts 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?
"List every folder and label of the mailbox" names a specific verb (list), a specific resource (folders and labels), and its scope (every). This is unmistakably distinct from the email-oriented siblings (list_emails, read_email, search_emails) without needing to name 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?
"Use this first when you do not know where a message lives" gives an explicit triggering condition and ordering relative to other tools. It also explains the payoff (returned names are valid inputs elsewhere), which is exactly the routing guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_emailARead-only
Read one full message, identified by the Message-ID returned by list_emails or search_emails. Returns headers, decoded text body, attachment names, and flags.
Args: message_id: Full Message-ID header value, including angle brackets. folder: Folder the message is in. max_chars: Maximum body characters to return; longer bodies are truncated.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No | INBOX | |
| max_chars | No | ||
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | No | |
| uid | Yes | |
| date | No | |
| links | No | |
| folder | Yes | |
| sender | No | |
| unread | No | |
| flagged | No | |
| subject | No | |
| received | No | |
| reply_to | No | |
| body_text | No | |
| truncated | No | |
| message_id | Yes | |
| recipients | No | |
| references | No | |
| size_bytes | No | |
| attachments | No | |
| body_markdown | No | |
| content_trust | No | |
| quoted_removed | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already signals a safe read, but the description adds value beyond the annotation by disclosing the return shape (headers, decoded body, attachment names, flags) and the truncation behavior via max_chars. Auth requirements and rate limits remain undisclosed.
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 one-sentence purpose covering both action and return, followed by a compact Args block with no filler. Every sentence 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?
Complete for a single-message read: identity source, required param format, truncation knob, and return contents are all covered, and an output schema exists so return values need no further elaboration.
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 burden, and it does: it explains that message_id must be the full Message-ID header including angle brackets, that folder locates the message, and that max_chars truncates longer bodies. Minor gap: no mention of the default values already present in the 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+resource (read one full message) plus scope ('one' vs the list/search siblings) and names where the Message-ID originates, which routes the agent away from list_emails/search_emails.
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 frames this as a follow-up to list_emails or search_emails, giving a clear usage context and an implied input source. It does not state when to prefer get_thread for conversation reading, so the exclusion is absent but the context is solid.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_attachmentA
Save one attachment into the local sandbox directory. Files are never overwritten and never leave the sandbox.
Args: message_id: Message-ID of the message. folder: Folder containing the message. filename: Exact attachment filename; omit when the message has exactly one. index: Attachment position (0-based) when filenames are ambiguous.
| Name | Required | Description | Default |
|---|---|---|---|
| index | No | ||
| folder | No | INBOX | |
| filename | No | ||
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| filename | Yes | |
| size_bytes | Yes | |
| content_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare not read-only, not destructive, not idempotent. The description adds genuinely new context: files are never overwritten and never leave the sandbox, which tells the agent the operation is contained and non-destructive to existing files. This is useful beyond what the annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior, then a compact Args block. Every line earns its place, though the Args formatting is slightly verbose for the amount of information conveyed.
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?
Complete for a mutation tool: an output schema exists so return values need no explanation, annotations cover the safety profile, and the description covers behavior and all parameters. Missing only explicit guidance on error/ambiguity handling beyond the filename/index hints.
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 delivers: each of the four parameters is explained, including the non-obvious conditional rules for filename ('omit when the message has exactly one') and index ('0-based when filenames are ambiguous'). Minor gap: no format hint for message_id or folder beyond the default.
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 ('Save one attachment') plus a clear destination ('local sandbox directory') and scope ('one attachment'). It is easily distinguished from list_attachments and export_email by the save-into-sandbox semantics, though it doesn't name a sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance, but the Args section implies the intended workflow (single attachment -> omit filename; ambiguous filenames -> use index). Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_emailsARead-only
Search messages, newest first. All filters combine with AND.
Args: query: Full-text across headers and body; empty matches everything. folder: Folder or label name to search in, as returned by list_folders. limit: Maximum number of messages to return (1-100). sender: Substring match on the From header. recipient: Substring match on the To header. subject: Substring match on the Subject header. since_days: Only messages received in the last N days. before_days: Only messages received before N days ago. unread_only: Only unread messages when true. has_attachment: Only messages carrying an attachment. IMAP cannot search on this, so up to 200 newest candidates are checked with BODYSTRUCTURE; the result reports how many were scanned and whether the set was truncated.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | No | ||
| folder | No | INBOX | |
| sender | No | ||
| subject | No | ||
| recipient | No | ||
| since_days | No | ||
| before_days | No | ||
| unread_only | No | ||
| has_attachment | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| scanned | No | |
| messages | No | |
| truncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint=true, the description discloses a non-obvious implementation constraint: IMAP cannot natively search attachments, so up to 200 newest candidates are probed via BODYSTRUCTURE and the result reports scanned/truncated counts. That is exactly the kind of caveat an agent needs to interpret partial results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and AND-combination rule are front-loaded in two short sentences, followed by a compact per-parameter list. Every line adds information; nothing is padded, and the attachment caveat is placed where it is relevant.
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, return values need not be described, and the description still notes that attachment searches report scan/truncation counts. Ten parameters at 0% schema coverage are all documented, so an agent has everything required to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does so for all ten parameters: full-text scope for query, substring matching semantics for sender/recipient/subject, relative-window meaning for since_days/before_days, and boolean triggers for unread_only/has_attachment. This is meaningfully more than the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search messages") plus an ordering guarantee ("newest first") and the AND semantics of filters. However, it never differentiates itself from the sibling search/list tools such as list_emails or get_thread, so the agent must infer which to choose.
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 clarifies how filters combine (AND), that an empty query matches everything, and points to list_folders for valid folder names, which is real usage guidance. It offers no when-to-use/when-not guidance relative to list_emails or get_thread, so routing between siblings is left implied.
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.
10 tool updates
v0.4.0- First observed
daily_digest - First observed
export_email - First observed
get_status - First observed
get_thread - First observed
list_attachments - First observed
list_emails - First observed
list_folders - First observed
read_email - First observed
save_attachment - First observed
search_emails
TDQS
Scored across 10 tools
Tools mostly target distinct actions or resources, but list_emails and search_emails overlap in filtering, and get_status and daily_digest both report unread counts. An agent can infer the difference from descriptions, but there is mild potential for misselection.
Names mostly follow a verb_noun pattern: list_folders, list_emails, search_emails, read_email, get_status, get_thread, list_attachments, save_attachment, export_email. daily_digest is the only noun-phrase outlier, a minor inconsistency.
10 tools is well-scoped for an email access server; each tool covers a distinct capability without obvious redundancy. The count is neither too thin nor too heavy.
The surface covers read-oriented mailbox operations well: folders, listing, search, read, threads, attachments, and export. However, it lacks send/compose, delete, move, and label/mark-read operations, which are notable gaps for a full email lifecycle.
Maintenance
Related MCP Connectors
- Lettio MCPOAutheu.lettio
Private, EU-hosted email for AI agents over JMAP: read, search, reply, organize, send.
- MailowsOAuthcom.mailows
Give AI agents their own email inboxes: list, read and send mail via scoped, revocable OAuth grants.
1 Your mailboxes in ChatGPT and Claude: Gmail, iCloud, Fastmail, any IMAP. Passwords stay yours.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables AI assistants to read and search Proton Mail inbox through Proton Mail Bridge, providing tools to list mailboxes, list messages, search messages, and fetch full message bodies. Read-only, with secure certificate pinning.417 npm1MIT
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to Proton Mail via MCP, enabling AI agents to list accounts/folders, search messages, and read emails using Proton Mail Bridge's local IMAP server.MIT
- AlicenseAqualityAmaintenanceEnables AI assistants to read, organize, and send Proton Mail through the local Proton Bridge, with careful gating for sending and attachment access.341Apache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to interact with a Proton Mail mailbox through Proton Bridge, supporting listing, searching, reading, sending, and organizing emails.-