A lightweight MCP server for reading IMAP email and creating draft replies. Built for ProtonMail Bridge.
This server demonstrates solid foundational quality with clear, well-structured tool definitions. All 14 tools have explicit schemas with typed parameters and substantive descriptions (100-200 chars typical). Naming follows verb_noun conventions consistently (find_emails, fetch_email_content, create_folder, etc.). Parameter descriptions are specific and actionable. However, there are notable gaps: (1) Most tools lack output schema documentation, responses are implicit/inferred rather than formally specified in the tool definition; (2) No error handling guidance in tool descriptions to help LLMs recover from failures; (3) No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite clear risk classifications in the provided metadata; (4) Several tools accept optional 'mailbox' parameters for optimization but do not document the performance impact or discovery mechanism; (5) No batch variants despite patterns suggesting agents call move_email, star_email, etc. in loops. The server implements a well-designed IMAP abstraction and respects the chat data model (accepting folder paths, using 'from'/'subject' for natural search), but falls short of A-grade polish on error recovery and composition patterns.
Create a new email draft. Requires recipient (to), subject, and body. Optional fields: cc, bcc, inReplyTo. The inReplyTo field can be a composite ID from find_emails to link the draft to an existing email thread. Returns {id, subject, to, date}.
Create a new folder. Use a path with the server's delimiter for subfolders (e.g. "INBOX/Receipts" or "Projects/2024"). Use list_folders first to discover the delimiter if unsure.
Download a specific attachment from an email. Requires the email id and the attachment id (obtained from fetch_email_content). Returns {id, filename, contentType, size, contentBase64} where contentBase64 is the base64-encoded file content.
Fetch the full content of a single email by its id. Returns {id, subject, from, to, date, body, attachments}. The attachments array contains metadata only (id, filename, contentType, size) — use fetch_email_attachment to download actual attachment data. Use an id obtained from any of the list_emails_* tools.
Search and filter emails. All parameters are optional — calling with no parameters returns the most recent emails from INBOX (default 50, max 200). Returns an array of {id, subject, from, date} objects sorted newest-first. The id is a globally unique identifier — use it with fetch_email_content to read the full email.
Output schemas not formally documented in tool definitions. Descriptions mention return structure (e.g. '{id, subject, from, date}') but this is not a machine-readable schema declaration. Downstream tool selection and response validation cannot rely on formal specifications.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) present in the tool definitions, despite metadata clearly classifying tools as READ_ONLY, WRITE, or REVERSIBLE. Without annotations, LLM clients cannot predict tool safety before invocation.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 58 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
List all starred emails across all folders, grouped by folder. Returns {totalCount, folders: [{folder, count, emails}]} sorted by folder path. Returns an array of {id, subject, from, date} objects sorted newest-first within each group. The id is a globally unique identifier — use it with fetch_email_content to read the full email.
List all folders in the email account. Returns an array of {path, name, delimiter} objects. Use the path value when specifying a folder in other tools.
List all starred emails in a folder. Returns an array of {id, subject, from, date} objects sorted newest-first. The id is a globally unique identifier — use it with fetch_email_content to read the full email.
Mark an email as read. Requires the email's id. Returns {id, read}.
Mark an email as unread. Requires the email's id. Returns {id, read}.
Move an email from one folder to another. Requires the email's id (from list_emails_* or fetch_email_content) and the destination folder to move it to. Returns {id, destination}.
Add a star (flag) to an email. Requires the email's id. Returns {id, starred}.
Remove a star (flag) from an email. Requires the email's id. Returns {id, starred}.
Replace an existing draft. Requires the draft's id and the updated subject, body, and recipient(s). Returns {id, subject, to, date}.
Error handling descriptions absent. Tool descriptions do not explain what can go wrong (e.g. 'email not found', 'folder does not exist', 'IMAP connection lost') or how an LLM should respond. LLMs lack guidance to retry, adjust parameters, or escalate.
Optional 'mailbox' parameter (folder hint) in 6 tools lacks documentation of performance implications. Description says 'for faster lookup' but does not explain what happens when omitted (full scan?) or when to use it (always? only for large mailboxes?).
No batch operations despite patterns suggesting agents loop over emails (e.g. 'star all emails from sender X', 'move emails matching pattern to folder'). Individual star_email/unstar_email/move_email calls waste tokens and latency.
find_emails returns max 200 results but no pagination tokens (cursor or offset). Users with thousands of emails cannot iterate beyond the first 200 without risk of duplicates or missing emails.
draft creation/update tools accept 'in_reply_to' as a 'composite ID' but do not document format or how to construct it from find_emails results. LLMs cannot reliably construct this parameter without trial-and-error.