Tools
Tools
Six tools, all of them reads. Every one is annotated readOnlyHint: true,
destructiveHint: false so a client can see the guarantee without trusting the
description.
Every tool except list_accounts is account-scoped and can be switched off per
account — see Permissions.
Shared arguments
| Argument | Type | Default | Meaning |
|---|---|---|---|
account | string | null | null | Account name. Optional when only one is configured. |
folder | string | "inbox" | A folder role (inbox, sent, junk, trash, drafts, archive) or a raw server folder name. |
limit | int | 25 | 1–200. |
offset | int | 0 | Messages to skip, for paging. |
list_accounts
List configured mail accounts and whether each is authenticated. Call this first if another tool reports an authentication problem.
Arguments: none.
Returns an array of:
{
"name": "outlook",
"provider": "outlook",
"email": "you@outlook.com",
"auth": "ok",
"detail": null
}
auth is one of ok, needs_auth or error; detail carries the reason when
it isn't ok.
list_folders
Folders in a mailbox with message and unread counts. Each folder has a
normalized role that is stable across providers, so you can ask for junk
without knowing the server calls it Junk Email.
Arguments: account.
Returns an array of:
{ "name": "Junk Email", "role": "junk", "messages": 128, "unseen": 4 }
role is one of inbox, sent, drafts, junk, trash, archive, other.
list_messages
Browse messages in a folder, newest first. Returns summaries only — no bodies.
Arguments: account, folder, limit, offset, and
unread_only (bool, default false).
Returns an array of message summaries.
search_messages
Server-side IMAP search, so it works over the whole folder without downloading anything. All supplied criteria are combined with AND. Results are newest first.
| Argument | Type | Meaning |
|---|---|---|
text | string | Free text, matched against headers and body |
from_ | string | Substring of the sender address or name |
subject | string | Substring of the subject |
since | date | On or after this date |
before | date | Strictly before this date |
unread_only | bool | Only unread mail |
Plus account, folder, limit and offset.
Returns an array of message summaries.
read_message
Read one message in full: headers, body text, and attachment metadata. HTML-only mail is converted to text.
BODY.PEEK, which is the IMAP fetch that leaves \Seen alone.| Argument | Type | Default | Meaning |
|---|---|---|---|
handle | string | required | A handle from list_messages or search_messages |
account | string | null | |
max_chars | int | 20000 | 200–200,000. Truncate the body beyond this many characters. |
Returns a message. If the folder was renumbered since the handle
was issued, you get a readable Error: ... string telling you to re-run the
search rather than the wrong message.
get_attachment
Download one attachment into the configured download directory.
| Argument | Type | Meaning |
|---|---|---|
handle | string | A handle from list_messages or search_messages |
part_id | string | The part_id from read_message's attachments |
account | string | Optional |
Returns:
{ "path": "/home/you/Downloads/rubit-mcp-mail/invoice.pdf",
"filename": "invoice.pdf",
"bytes": 48213 }
Files are only ever written inside that one directory — the filename is sanitized, cannot escape upwards, and never clobbers an existing file. The mailbox itself is not modified.
Return shapes
Message summary
{
"handle": "WyJvdXRsb29rIiwiSU5CT1giLDEsNDJd",
"subject": "Your invoice",
"from": [{ "name": "Billing", "email": "billing@example.com" }],
"to": [{ "name": null, "email": "you@outlook.com" }],
"date": "2026-09-14T10:03:11Z",
"seen": false,
"flagged": false,
"answered": false,
"has_attachments": true,
"size": 48213,
"message_id": "<abc@example.com>"
}
Message
Everything in a summary, plus:
| Field | Type | Meaning |
|---|---|---|
cc | address list | |
reply_to | address list | |
body | string | The text |
body_format | "text" | "html-converted" | "none" | Which part you got |
truncated | bool | Whether max_chars cut it |
attachments | Attachment[] | { part_id, filename, content_type, size } |
Handles
list_messages and search_messages return opaque handles. Pass one to
read_message or get_attachment.
A handle is base64url of [account, folder, uidvalidity, uid]. It carries the
folder's UIDVALIDITY, so if the mailbox is renumbered you get a clear
"re-run the search" error rather than the wrong message. It is deliberately
plain ASCII: some MCP clients mangle raw control characters when a handle
round-trips through their display layer before the model retypes it.