Notmuch
A read-first MCP server providing access to a local Notmuch email database, enabling LLM clients to search, read, and analyze mail, with optional write capabilities for drafts, tags, and exports.
Core Capabilities (Always Available)
Search mail (
mail_search): Full notmuch query syntax, with paging, sorting, and thread/message granularity.Read threads/messages (
mail_read_thread,mail_read_message): Retrieve entire threads or individual messages.Thread overview (
mail_thread_overview): One-line-per-message summary (date, size, sender) for quick assessment.Find related threads (
mail_related_threads): Heuristic overlap of subject and participants.Pending mail (
mail_pending): Identify threads you owe a reply to or are waiting on.Count mail (
mail_count): Cheap message/thread counts without fetching content.Resolve addresses (
mail_list_addresses): Map names to actual email addresses, ranked by usage.Attachments: List (
mail_list_attachments), read content (mail_read_attachment– supports text, PDF, images, office docs, ICS), and find across searches (mail_find_attachments).Prepare reply (
mail_prepare_reply): Compute reply/reply-all/forward headers and quoted body (read-only).List scopes (
mail_list_scopes): Discover pre-configured search scopes.
Optional Write Capabilities (Require Flags)
Drafts (
--allow-drafts): Create (mail_create_draft) or update (mail_update_draft) plain-text drafts with attachments in a local maildir.Tagging (
--allow-tags): Add or remove tags on messages (mail_tag).Export (
--allow-export DIR): Save raw attachment bytes (mail_save_attachment) or generate a Gource visualization of mailbox history (mail_export_gource).
Limitations
Never sends email.
Never modifies message content (only tags and drafts).
Reads/writes only within the notmuch database, drafts maildir, and export directory.
mcp-server-notmuch
An MCP server that exposes a local notmuch email database to an LLM client such as Claude. It is read-first: searching, reading, and understanding mail is always available; writing anything (drafts, tags, exported files) requires an explicit opt-in flag and is confined to clearly bounded locations.
It never sends mail. There is no send capability anywhere in this codebase, in any mode, with any flag. Drafts are written to a local maildir for you to review and send yourself in a real mail client.
What it does
Searches and reads your mail (threads, single messages, attachments, calendar invites, office documents, images) via the real
notmuchCLI.Understands scopes: a named, pre-configured notmuch query (e.g. "personal mail" vs. "mailing lists") that every search is confined to unless you ask otherwise.
Answers "what's still unanswered" and "who owes me a reply" (
mail_pending), "has this come up before" (mail_related_threads), and gives a token-cheap overview of a long thread before you read all of it (mail_thread_overview).Optionally composes and revises plain-text drafts (
--allow-drafts), tags messages (--allow-tags), or exports attachments and a Gource visualization of your mailbox history to a directory you name (--allow-export DIR).
Related MCP server: notmuchproxy
What it does not do
It does not send mail. Ever.
It does not modify your mail in any way unless you pass
--allow-tags(tagging) or--allow-drafts(writing a new file into a drafts maildir). Neither flag lets it touch existing messages' content.It does not read or write outside the notmuch database, the configured drafts maildir, and (only with
--allow-export) the configured export directory.It does not require or use the notmuch2 Python bindings, so no compiler is needed to install it.
Install
From PyPI (once published)
$ uvx --prerelease=allow mcp-server-notmuch --helpFrom source
$ git clone https://github.com/hgn/mcp-server-notmuch
$ cd mcp-server-notmuch
$ uv pip install --prerelease=allow -e .
$ mcp-server-notmuch --helpThe --prerelease=allow is required because this project pins a
pre-release of the mcp SDK (see SDK version below); it is
not optional.
System requirements
notmuch(the CLI, not just the library) onPATHor pointed to vianotmuch.binaryin the config.poppler-utils(pdftotext) to read PDF attachments. Without it,mail_read_attachmenton a PDF names the missing package.pandocorlibreofficeto read office documents (doc/docx/odt/rtf). Without either, the error names both options.Optionally,
Pillow(pip install 'mcp-server-notmuch[image]') to let oversized image attachments be downscaled instead of refused.Optionally, Gource to actually play back the log
mail_export_gourcewrites.
MCP client configuration
Claude Code
Read-only (the default: search and read tools only):
$ claude mcp add notmuch -- uvx --prerelease=allow mcp-server-notmuchWith drafts enabled (also allows revising/tagging as needed):
$ claude mcp add notmuch -- uvx --prerelease=allow mcp-server-notmuch --allow-draftsOr by hand in .mcp.json:
{
"mcpServers": {
"notmuch": {
"command": "uvx",
"args": ["--prerelease=allow", "mcp-server-notmuch", "--allow-drafts"]
}
}
}Claude Desktop
Add to claude_desktop_config.json (read-only default):
{
"mcpServers": {
"notmuch": {
"command": "uvx",
"args": ["--prerelease=allow", "mcp-server-notmuch"]
}
}
}With drafts enabled:
{
"mcpServers": {
"notmuch": {
"command": "uvx",
"args": ["--prerelease=allow", "mcp-server-notmuch", "--allow-drafts"]
}
}
}Configuration
The server reads $XDG_CONFIG_HOME/mcp-server-notmuch/config.toml
(~/.config/mcp-server-notmuch/config.toml if XDG_CONFIG_HOME is unset),
or a path given with --config. A missing file is not an error: the server
falls back to the system notmuch binary and a single built-in scope
all with an empty query. Once a file exists, [scopes] is authoritative
and all is no longer implied.
See config.example.toml for a fully commented
reference file. Summary of every key:
Section | Key | Default | Meaning |
|
|
| Path or bare name of the notmuch binary. |
| notmuch's own default | Path passed as | |
|
| unset (unlimited) | Message body truncation point; unset means full body every time. |
| unset (unlimited) | Attachment/office/calendar text truncation point; unset means full text every time. | |
|
| Image size ceiling; downscaled with Pillow if larger, else refused. | |
|
| (required once | Scope used when a tool call omits |
|
| — | A notmuch query ANDed with every search using this scope. |
|
| Shown by | |
|
| unset | Root of a maildir ( |
| unset |
| |
| unset | Plain-text signature file, appended on request. | |
|
| Hard-wrap width for drafted plain text. | |
|
| Ceiling on draft attachments' combined size. | |
|
| notmuch's | Your own address(es); used to exclude yourself from reply-all and to detect |
mail_create_draft/mail_update_draft refuse to run unless both
drafts.maildir and drafts.from are set. mail_pending direction="waiting" needs [identity] addresses (or a readable notmuch
user.primary_email) to know which address is "you".
Nothing is truncated by default. This is a local, fast mailbox, not a
rate-limited API: mail_search, mail_pending, mail_related_threads,
mail_list_addresses, mail_find_attachments and mail_export_gource all
return every matching row unless a tool call passes an explicit limit,
and message bodies/attachment text come back in full unless
limits.max_body_chars/limits.max_attachment_chars are set. Whenever an
explicit limit or char cap does cut something, the output says so:
"Showing N of TOTAL ..." plus a hint to omit limit to see everything.
There is no silent, invisible ceiling anywhere in this server.
Scope resolution: a tool's scope argument names a configured scope; its
query is ANDed with the caller's query, both sides parenthesized
((scope_query) and (user_query)), so an or on either side cannot leak
past the other. An unknown scope name is an error listing the configured
scopes; scope="all" is never silently unfiltered unless you define a
scope literally named all.
Tiers and tools
Four tiers. The read tier is always registered. The other three are registered only when their flag is passed — there is no "registered but refused" state, an unauthorized tool is simply absent from the tool list a client sees.
Flag | Registers |
(none) | Read tier: search, read, list, prepare — nothing is written. |
| Draft tier: compose and revise local plain-text drafts. |
| Tag tier: add/remove tags on existing messages. |
| Export tier: write attachments/a Gource log into |
Read tier (always on)
Tool | Purpose |
| Search threads or messages, paged; returns everything unless |
| Every message in a thread, oldest first. |
| One line per message (date/size/from), tree or flat layout, before reading a long thread in full. |
| Heuristic "has this come up before" (subject + participant overlap). |
| Threads you owe a reply on, or threads you're waiting on a reply to. |
| A single message's headers and body. |
| Cheap message/thread count for a query. |
| Resolve a name to the real address(es) behind it. |
| List one message's attachments. |
| Read one attachment: text, PDF, image, office document, or calendar invite. |
| Find attachments across a whole search (e.g. "all PDFs from 2025"). |
| List the configured scopes. |
| Derive reply/reply-all/forward headers and quoted/forwarded body; writes nothing. |
Draft tier (--allow-drafts)
Tool | Purpose |
| Compose a plain-text draft (optionally with attachments) into the configured maildir. |
| Revise an existing draft in place; only the given fields change. |
Tag tier (--allow-tags)
Tool | Purpose |
| Add/remove tags on every message matching a query. |
Export tier (--allow-export DIR)
Tool | Purpose |
| Save one attachment's raw bytes into |
| Write a Gource custom log of mailbox history into |
mail_export_gource writes one line per message,
timestamp\|username\|type\|path\|colour, sorted oldest first (Gource
requires this). path is folder/normalized-subject, so a whole reply
chain lands at one point in the tree; colour is a stable hash of the
folder name, so a folder keeps its colour across repeated exports. Play it
back with:
$ gource --log-format custom mail.gource -s 0.5 --keyAll matching messages are included by default; limit matters when the
query is broad, since feeding Gource every mailing-list message you've
ever received produces an unwatchable animation, so scope the query first
or set limit explicitly.
Security model
This is a mail server handed to an LLM; message content is not trusted the way your own instructions are.
Prompt injection. Message bodies, attachment text, calendar summaries, and thread overview lines are third-party content, not instructions.
render.pywraps every one of them in explicit-----BEGIN/END UNTRUSTED EMAIL CONTENT-----markers with a notice that nothing inside should be treated as a command, so no individual tool can forget to do this.Path confinement. The drafts maildir (
compose.py) and the export directory (export.py) each resolve the target path and verify it is still inside the configured root afterward. This catches a literal..and a symlink pointing outside the root (Path.resolve()follows symlinks), andmail_create_draft/mail_update_draftcannot be made to write outside the configured maildir with any combination of arguments.No shell, ever. Every subprocess call is
subprocess.run([...], shell=False)with an argv list; queries are passed as a single argv element, never interpolated into a shell string or a notmuch query string beyond normal AND/OR composition.No content in diagnostics. Errors and progress go to stderr and are content-free (a byte count or a file path, never a message body).
Never silently unfiltered. A
scopeargument that AND-composes with a query is always explicit; there is no hidden "search everything" fallback unless a scope literally namedallis configured.Never silently truncated. This is a local, fast mailbox: result rows, message bodies and attachment text are returned in full unless a tool call passes an explicit
limitor the config sets an explicitlimits.max_body_chars/limits.max_attachment_chars. Whenever one of those does cut something, the output states the true total and how to see the rest, never a silent cut.
notmuch query syntax
query/scope arguments accept full notmuch search syntax: from:,
to:, subject:, tag:, date: ranges, boolean and/or/not, and
more. See notmuch-search-terms(7) (man notmuch-search-terms) for the
complete reference.
SDK version
Targets MCP spec 2026-07-28 and pins mcp==2.0.0b2, a pre-release of
the Python SDK built for that spec. Once the spec and a matching stable SDK
release ship, this pin moves to the stable release; until then, every
install (uv pip install, uvx) needs --prerelease=allow.
Development
$ make # fmt + lint + test
$ make test # pytest (skips cleanly if notmuch is not installed)
$ make lint # ruff format --check + ruff check
$ make help # list all targetsTests build a small crafted maildir and run real notmuch commands against
it; nothing touches your real mail. CI runs on Python 3.11, 3.12 and 3.13
with notmuch installed via apt.
License
MIT, see LICENSE.
Available Tools
13 toolsmail_countCount mailARead-only
Count messages or threads matching a query, without fetching any of them.
Cheap way to check whether a correspondent, subject or thread exists at all before running a full mail_search, e.g. "how many mails did I get from X" (count="messages", the right default) versus "how many separate conversations" (count="threads"). Not a substitute for mail_search when you need to see the matches themselves.
Args:
query: A notmuch query, e.g. 'from:alice'. See notmuch-search-terms(7)
for the full syntax, including relative date ranges such as
'date:this_year..', 'date:last_month..', 'date:1Y..' and
'date:2026-01-01..2026-06-30'.
scope: Name of a configured scope to AND with query (see
mail_list_scopes). Defaults to the configured default scope.
count: 'messages' or 'threads'.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | messages | |
| query | Yes | ||
| scope | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds valuable behavior: 'without fetching any of them' clarifies that no message content is retrieved, and 'cheap way' signals performance characteristics. This goes beyond the annotation's basic safety profile, though it doesn't cover all possible edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core statement, followed by usage context and an Args section. Every sentence adds value—examples for query syntax, scope behavior, and count semantics are all relevant. No fluff.
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 count tool with no output schema, the description sufficiently implies the return value (a count) while covering query syntax, scope, and count modes. The mention of default scope and examples of date ranges makes it complete for the 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?
Even though schema property descriptions are absent (0% coverage), the description thoroughly explains each parameter: the query syntax with notmuch examples and date ranges, the scope default behavior, and the count options ('messages' or 'threads'). This fully compensates for the schema's lack of descriptions.
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 'Count messages or threads matching a query'—a specific verb and resource that clearly states the tool's function. It distinguishes itself from siblings by explicitly stating it doesn't fetch matches and is not a substitute for mail_search.
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?
Provides explicit usage context: it's a 'cheap way to check whether a correspondent, subject or thread exists' before running a full mail_search, and explicitly says 'Not a substitute for mail_search when you need to see the matches themselves.' This gives clear when-to-use and when-not-to-use guidance relative to alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_find_attachmentsFind mail attachmentsARead-only
Find attachments across a whole search, not just within one message.
Use this for questions like "all invoices from 2025" or "which PDFs
did I get from the accountant", where the attachment itself, not the
message, is what you are looking for. For a single message's
attachments, use mail_list_attachments instead. Note that notmuch's
own query syntax already supports 'attachment:*.pdf' and
'tag:attachment' inside query if you want to filter at the notmuch
level too.
Args:
query: A notmuch query selecting the messages to scan for attachments.
scope: Name of a configured scope to AND with query (see
mail_list_scopes). Defaults to the configured default scope.
type: Filter by 'pdf', 'image', 'doc' (office documents), or a raw
filename extension such as 'png' or 'xlsx'. Omit for no filter.
limit: Maximum number of attachment rows to return. Omit for all
results (the default); set it only to cap the number returned,
and when it truncates the total is still reported.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | ||
| limit | No | ||
| query | Yes | ||
| scope | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as readOnlyHint=true and openWorldHint=false, which covers the safety profile. The description adds behavioral context beyond annotations: it explains the search scope (across a whole search), the `limit` parameter's truncation behavior ('when it truncates the total is still reported'), and scope defaulting. It does not discuss auth or return format, but for a read-only search tool this is adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: a one-sentence purpose, then usage guidance with examples, a note about query-level filtering, and an Args section. Every sentence adds value—no filler or repetition. The front-loaded purpose makes it easy to scan, and the Args section is formatted for quick reference.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 4 parameters, no output schema, and no enums, this description covers the core usage well: what the tool does, when to use it, parameter semantics, and limit behavior. It does not describe the structure of returned attachment rows (e.g., fields like filename, size, message ID), which could be helpful given there is no output schema. Still, the lack of such detail does not prevent correct invocation for the described purposes.
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 fully compensate. It does: each parameter (query, scope, type, limit) has a clear explanation with examples and default behavior. For instance, `type` is defined with categories and raw extensions, and `limit` clarifies that omission means all results while truncation still reports the total.
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 'Find attachments across a whole search, not just within one message', which is a specific verb+resource+scope statement. It clearly distinguishes itself from the sibling mail_list_attachments by explaining the different scope ('a whole search' vs 'a single message').
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 provides explicit when-to-use guidance with concrete examples ('all invoices from 2025', 'which PDFs did I get from the accountant') and an explicit alternative for single-message cases: 'use mail_list_attachments instead'. It even notes the notmuch query-level filtering alternative (attachment:*.pdf, tag:attachment).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_list_addressesList mail addressesARead-only
Resolve a name or query into the concrete email addresses behind it.
Searching from: directly is unreliable: it also matches mail that merely mentions the name in a display name (e.g. a share notification like "Kathrin Pietsch (via Google Keep) <keep-shares@ google.com>"), and a name can belong to more than one real address or person. Call this tool first whenever you only have a name, then search or count using the address(es) it returns.
Args:
query: A notmuch query, typically a name fragment, e.g. 'kathrin'.
scope: Name of a configured scope to AND with query (see
mail_list_scopes). Defaults to the configured default scope.
output: 'sender' (addresses this query's messages were From),
'recipients' (addresses in To/Cc/Bcc), or 'count' (sender
addresses ranked by occurrence count, the way to find
someone's most-used address among several).
limit: Maximum number of addresses to return. Omit for all results
(the default); set it only to cap the number returned, and
when it truncates the total is still reported.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| scope | No | ||
| output | No | sender |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
While annotations provide readOnlyHint=true, the description adds critical behavioral details: it explains that query is a notmuch query, describes the three output modes and their semantics, and discloses limit truncation behavior ('when it truncates the total is still reported'). It also surfaces a subtle pitfall about display-name matching, which goes well beyond annotation data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the core purpose, then usage rationale, then detailed parameters. Every sentence earns its place—there is no fluff or repetition. The Args block follows a consistent, scannable format, making the information easy to parse.
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 four parameters and no output schema, the description covers all essential aspects: purpose, usage context, parameter semantics, and even edge-case behavior (unreliable direct matching, truncation reporting). It provides enough information for an agent to select and invoke the tool correctly without external docs.
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 input schema provides no descriptions (0% coverage), so the description carries the full burden. Each parameter receives thorough explanation: query with an example, scope with a reference to mail_list_scopes, output with explicit modes and meanings, and limit with default and truncation semantics. This fully compensates for the schema's silence.
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 clear, specific verb-resource pairing: 'Resolve a name or query into the concrete email addresses behind it.' It distinguishes itself from sibling tools by focusing on address resolution rather than message search, read, or count operations. The purpose is immediately understandable and not a tautology.
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 explicitly tells the agent when to use this tool: 'Call this tool first whenever you only have a name, then search or count using the address(es) it returns.' It also warns against the unreliable alternative of using from:<name> directly in search, providing concrete when-not-to-use guidance and setting expectations for subsequent steps.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_list_attachmentsList mail attachmentsARead-only
List a message's attachments (part index, filename, content type, size).
Call this before mail_read_attachment to learn valid part_index values; it does not return attachment content itself.
Args: message_id: A Message-ID as seen in mail_search/mail_read_thread output.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral context beyond the readOnlyHint annotation by stating that the tool returns metadata (part index, filename, content type, size) and not content. This is useful, though the annotation already covers safety.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: it starts with the main purpose, then gives usage guidance, and ends with an Args section. Every sentence earns its place without unnecessary fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool without an output schema, the description is complete: it lists the return fields, states what it does not return, and positions it relative to sibling tools. No critical information 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 compensates by explaining that message_id should be 'as seen in mail_search/mail_read_thread output', providing source context. This adds meaningful value over the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'List a message's attachments (part index, filename, content type, size)'. It uses a specific verb and resource, and explicitly distinguishes itself from sibling tools like mail_read_attachment by noting it does not return 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?
The description gives explicit usage guidance: 'Call this before mail_read_attachment to learn valid part_index values'. It also clarifies what the tool does not do ('does not return attachment content itself'), helping the agent choose the right tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_list_scopesList mail scopesARead-only
List the configured scopes with their notmuch query and description.
Call this to discover valid scope values for mail_search/mail_count/
mail_tag instead of guessing scope names.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true. The description adds value by specifying the output includes notmuch query and description, behaviorally enriching beyond the annotation.
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: first states purpose, second provides usage guidance. Front-loaded, no wasted words, perfectly concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with no output schema, the description explains what is returned and why to use it. Could be more explicit about output format, but sufficient given no schema.
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?
Tool has 0 parameters with 100% schema coverage (empty schema), so description does not need to cover parameter meaning. Baseline for 0 params is 4.
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 clearly states it lists configured scopes with their notmuch query and description, and explicitly mentions its purpose for discovering valid scope values for other mail tools. This distinguishes it from all sibling tools.
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 explicitly instructs to call this tool to discover valid scope values for mail_search/mail_count/mail_tag instead of guessing, providing clear context and a specific alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_pendingPending mailARead-only
Threads that need attention: mail owed by you, or mail you are waiting on.
direction='owed': threads matching scope that no message has ever
been tagged 'replied' on, i.e. mail you have not answered. Use this
for "what do I still need to reply to".
direction='waiting': threads where your own address sent the most recent message and nobody has responded since. Use this for "who owes ME a reply". Needs at least one address configured under [identity] addresses in the config (normally defaulted automatically from notmuch's own user.primary_email/user.other_email); without that, this direction raises an actionable error rather than guessing.
Both directions sort oldest (most overdue) first, since age is the point. This is not a substitute for mail_search when you want to see the messages themselves, only for triaging what is outstanding.
Args: direction: 'owed' (you have not replied) or 'waiting' (you are waiting on a reply). older_than: Only include threads whose relevant date is at least this old, e.g. '14d', '2w', '3m', '1y'. Omit for no age floor. scope: Name of a configured scope to restrict the search (see mail_list_scopes). Defaults to the configured default scope. limit: Maximum number of threads to return. Omit for all results (the default); set it only to cap the number returned, and when it truncates the total is still reported.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| scope | No | ||
| direction | No | owed | |
| older_than | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safe-read nature is covered. The description adds valuable behavioral context: both directions sort oldest first because 'age is the point', the 'waiting' direction requires identity addresses and raises an actionable error if missing, and the limit parameter still reports the total when truncating. This is strong supplementary transparency 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 description is organized into clear paragraphs and an Args section. Every sentence earns its place: both directions are explained with use cases, sorting is justified, the config dependency for 'waiting' is disclosed, and the relationship to mail_search is stated. It is thorough but not bloated, with no redundant phrasing.
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?
Given the tool's complexity (two directions, config dependency, sorting, and four parameters with nuances), the description is fully complete. It covers return-ordering behavior, error conditions, parameter semantics, and when to use alternatives. Although there is no output schema, the description notes that the total is reported even when truncating, which addresses response expectations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the full burden, and it does. Every parameter is explained with concrete examples: direction lists values and meaning, older_than gives formats like '14d', scope references mail_list_scopes for configuration, and limit explains its default and truncation behavior. This fully compensates for the schema's lack of descriptions.
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 'Threads that need attention: mail owed by you, or mail you are waiting on,' which specifies the exact verb (list threads needing attention) and resource (mail threads). It differentiates from the sibling mail_search by explicitly stating 'This is not a substitute for mail_search when you want to see the messages themselves,' making its purpose unmistakable.
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 provides explicit usage scenarios: direction='owed' is for 'what do I still need to reply to' and direction='waiting' for 'who owes ME a reply'. It also names the sibling alternative (mail_search) and explains when not to use this tool, saying it is only for triaging outstanding mail, not for viewing messages.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_prepare_replyPrepare mail replyARead-only
Derive reply/forward headers and the quoted or forwarded body.
This is read-only: it computes what a reply or forward should look like but writes nothing. Pass the result's To/Cc/Subject/In-Reply-To to mail_create_draft (draft tier) if you want it actually saved as a draft.
Args: message_id: A Message-ID as seen in mail_search/mail_read_thread output. quote: Whether to include the original body (quoted with '> ' for reply/reply-all, or as a labelled forwarded block for forward). mode: 'reply' (sender only, honouring Reply-To), 'reply-all' (all original recipients minus your own configured addresses, honouring Mail-Followup-To, which is what mailing lists set and what makes the difference between a correct reply and an embarrassing one), or 'forward' (no In-Reply-To/References, subject gets exactly one 'Fwd:' prefix, body is a labelled forwarded block with the original headers, not an interleaved quote).
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | reply | |
| quote | No | ||
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reinforces the readOnlyHint annotation by stating it 'computes' and 'writes nothing.' It adds behavioral details such as quoting behavior ('> ' for replies, labelled forwarded blocks for forwards), subject prefix rules ('Fwd:' exactly once), and header handling (In-Reply-To/References). This goes well beyond the annotation 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 description is front-loaded with a one-sentence summary, followed by a read-only note and a direct pointer to mail_create_draft. The Args section is cleanly formatted and every sentence adds value – no fluff or repetition of schema metadata.
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?
Given the tool has no output schema and only three parameters, the description covers the tool's purpose, output (headers and body), mode variations, and the follow-up action. It also clarifies the read-only nature, making it complete for an agent to select and invoke 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 coverage is 0%, so the description compensates by defining message_id as a Message-ID from mail_search/mail_read_thread output, quote as including the original body with specific formatting, and mode with three detailed options including Mail-Followup-To semantics. Each parameter is fully explained beyond the schema's type/default fields.
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 ('Derive') plus the resource ('reply/forward headers and the quoted or forwarded body'), clearly distinguishing it from read-only tools like mail_read_message and mail_read_thread. It also names the output artifacts (To/Cc/Subject/In-Reply-To) and the body format, making the tool's function unmistakable.
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 explicitly instructs the agent to pass the result to mail_create_draft for persistence, and it specifies that this tool itself writes nothing, establishing when to use it versus the draft-saving alternative. The mode parameter is explained with concrete semantics (reply/reply-all/forward) and pitfalls (honoring Mail-Followup-To), giving clear usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_read_attachmentRead mail attachmentARead-only
Read one attachment: text, PDF, image, office document or calendar invite.
Dispatches by content type: text/* and PDF (via pdftotext) come back as text; image/* comes back as an actual image the model can look at (downscaled if oversized and Pillow is installed, otherwise refused with its size); office documents (doc/docx/odt/rtf) are converted to text via pandoc or libreoffice; calendar invitations (text/calendar, .ics) are rendered as a readable summary (method, time, location, organizer, attendees with their response status). Call mail_list_attachments first to get a valid part_index. Archives and other binary formats are not supported and raise an explanatory error.
Args: message_id: A Message-ID as seen in mail_search/mail_read_thread output. part_index: The 1-based part index from mail_list_attachments.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | ||
| part_index | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only indicate readOnlyHint, but the description goes far beyond by detailing content-type dispatch (pdftotext, Pandoc/LibreOffice, etc.), image handling with downscaling/refusal, error behavior for unsupported formats, and calendar invite summary rendering. This is rich behavioral context with no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise yet complete, starting with a clear summary, followed by necessary technical details, and ending with parameter definitions. No sentence is wasteful; the structure is logical and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description covers expected return formats (text, image, summary) and error cases. It also notes prerequisites and limitations, making the tool's behavior fully comprehensible for an agent.
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?
Although schema coverage is 0%, the description includes an 'Args' section that explains both parameters. message_id is tied to specific sources ('as seen in mail_search/mail_read_thread output') and part_index is defined as '1-based part index from mail_list_attachments', adding meaning the schema lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific statement: 'Read one attachment: text, PDF, image, office document or calendar invite.' This identifies the verb, resource, and scope, and distinguishes it from sibling tools like mail_list_attachments and mail_read_message by focusing on attachment 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?
Explicit guidance is provided: 'Call mail_list_attachments first to get a valid part_index.' It also clarifies unsupported types ('Archives and other binary formats are not supported') and explains the prerequisite, making the when-to-use and when-not-to-use clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_read_messageRead mail messageARead-only
Return a single message's headers and body.
Use this for one specific message. For an entire conversation in order, use mail_read_thread instead.
Args: message_id: A Message-ID as seen in mail_search/mail_read_thread output, with or without angle brackets or the 'id:' prefix. response_format: 'concise' (From/Date/Subject, short body) or 'detailed' (full headers, full body up to the configured limit).
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | ||
| response_format | No | detailed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, and the description adds meaningful behavioral context beyond that: it describes the response_format behaviors ('concise' vs 'detailed') and discloses that the detailed body is truncated by a configured limit. This goes beyond the annotations, though it could have mentioned error handling or idempotency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is moderately sized and well-structured, starting with a one-line summary, then a usage note, then an Args list. Every sentence contributes value with no fluff, though it is slightly longer than the minimal needed.
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?
Given only two parameters and no output schema, the description adequately covers what the tool returns (headers and body), the output format choices, and how it relates to sibling tools. It provides enough information for an agent to invoke 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?
The input schema has zero property descriptions (0% coverage), but the description's Args section fully compensates. It explains message_id format (with/without angle brackets or 'id:' prefix) and the two response_format options with their effects. This adds substantial meaning beyond 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?
The description clearly states the tool returns a single message's headers and body, using a specific verb and resource. It also distinguishes itself from the sibling mail_read_thread by explicitly noting the difference between a single message and an entire 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?
The description provides explicit guidance on when to use this tool ('for one specific message') and names the alternative for conversations (mail_read_thread). It also includes parameter-specific usage details, such as how to format message_id and the two response_format options.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_read_threadRead mail threadARead-only
Return every message in a thread, oldest first, with '--- [N/M] ---' separators.
Use this once mail_search has identified a thread_id and you need the conversation in order. For a single message, use mail_read_message instead. For a long thread, consider calling mail_thread_overview first: it shows one line per message (date, size, from, subject changes) so you can pick the one or two messages worth reading in full here, instead of pulling the whole thread.
Args: thread_id: A thread identifier as returned by mail_search (with or without the 'thread:' prefix). response_format: 'concise' (From/Date/Subject, short body) or 'detailed' (full headers, full body up to the configured limit).
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | Yes | ||
| response_format | No | detailed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds substantial behavioral context beyond this: ordering, message separators, response_format differences ('concise' vs 'detailed'), handling of the 'thread:' prefix, and the caveat about long threads and configured limits. No contradictions with 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?
Every sentence is functional: output format, usage context, alternatives, and parameter details. The structure is clear, front-loaded with the primary purpose, and no redundant wording despite being more detailed than typical.
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?
The tool is a read-only operation with two parameters and no output schema. The description covers output ordering, format, parameter semantics, and usage guidance. It is complete for the tool's complexity and leaves no critical gaps.
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 fully carries parameter documentation. It explains thread_id as 'A thread identifier as returned by mail_search (with or without the 'thread:' prefix)' and response_format with concrete examples of what each option returns. This exceeds baseline for zero-coverage parameters.
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+resource: 'Return every message in a thread, oldest first, with '--- [N/M] ---' separators.' It clearly distinguishes from siblings by explicitly naming mail_read_message for single messages and mail_thread_overview for long threads.
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?
Provides explicit when-to-use ('Use this once mail_search has identified a thread_id'), when-not-to-use ('For a single message, use mail_read_message instead'), and an alternative strategy for long threads ('consider calling mail_thread_overview first'). This fully covers the decision space.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_searchSearch mailARead-only
Search notmuch and return a paged summary, at thread or message granularity.
Use granularity="threads" for "what conversations are there about Y": each row is one thread, dated by its newest (or oldest) matched message, with an authors column that can mix matched and unmatched participants (see the legend in the output). Use granularity="messages" for "the last mail from X" or "how many mails did X write": each row is one matching message with its own date, from and subject.
Do not use this to fetch full bodies (use mail_read_message / mail_read_thread) or to turn a person's name into addresses first (use mail_list_addresses; from: also matches notification mail that merely mentions the name).
Args:
query: A notmuch query, e.g. 'from:alice subject:invoice'. See
notmuch-search-terms(7) for the full syntax, including
'date:this_year..', 'date:last_month..', 'date:1Y..' and
'date:2026-01-01..2026-06-30' for date ranges.
scope: Name of a configured scope to AND with query (see
mail_list_scopes). Defaults to the configured default scope.
limit: Maximum number of rows to return. Omit for all results (the
default); set it only to cap the number returned, and when it
truncates the total is still reported.
offset: Number of matching rows to skip, for paging through
results already seen.
response_format: 'concise' (one line per row) or 'detailed' (adds
message counts/tags for threads, or the message_id for messages).
granularity: 'threads' (one row per conversation) or 'messages'
(one row per matching message).
sort: 'newest-first' or 'oldest-first'.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | newest-first | |
| limit | No | ||
| query | Yes | ||
| scope | No | ||
| offset | No | ||
| granularity | No | threads | |
| response_format | No | concise |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses paging behavior, truncation reporting, mixing of matched/unmatched authors in the authors column, and output legend. Despite readOnlyHint being already declared, the description adds substantive behavioral context beyond the annotation.
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?
Well-structured with usage scenarios up front and a clear Args list. Bullet points make parameters easy to scan, and every sentence adds value without unnecessary verbosity.
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-param search tool with no output schema, the description covers return values, paging, granularity options, parameter semantics, and alternative tools. It is self-sufficient and complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description fully compensates by explaining all 7 parameters with examples, defaults, and syntax hints. The query parameter even points to external documentation and gives date range examples.
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 clearly states the tool searches notmuch and returns a paged summary at thread or message granularity. It distinguishes from siblings like mail_read_message, mail_read_thread, and mail_list_addresses by explicitly stating what this tool does not do.
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?
Provides explicit when-to-use guidance for granularity='threads' vs 'messages' with concrete examples. It also names alternatives for fetching full bodies and address lookup, including a warning about from:<name> matching notification mail.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mail_thread_overviewThread overviewARead-only
One line per message: index, date, size, from, and a marker when the subject changes from the thread's root subject.
Use this before mail_read_thread on any thread you have not looked at yet, especially a long one: it costs a fraction of the tokens and lets you decide which one or two messages to actually read in full, instead of pulling all eighty. Do not use it in place of mail_read_thread when you already know you need the full content.
Args: thread_id: A thread identifier as returned by mail_search (with or without the 'thread:' prefix). layout: 'tree' (the actual reply nesting, from notmuch's own thread structure; for a patch series with parallel discussion strands this is materially different from linear order) or 'flat' (linear oldest-first order, matching mail_read_thread's [N/M] numbering).
| Name | Required | Description | Default |
|---|---|---|---|
| layout | No | tree | |
| thread_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, and the description adds valuable behavior: output structure, layout semantics ('tree' vs 'flat'), and token efficiency compared to mail_read_thread. It does not contradict annotations, and adds meaningful context beyond the safety hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately sized and well-structured: it starts with the output format, then gives usage guidance, then details arguments. Every sentence earns its place with no redundant or vague 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?
The description is highly complete for a read-only overview tool: it specifies output fields, layout options, usage context, and parameter origins. Minor gaps like pagination or max message limits are not addressed, but the description is sufficient for the tool's purpose.
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 fully compensates. thread_id is explained as a value from mail_search with/without 'thread:' prefix, and layout is thoroughly described with tree/flat semantics and its relation to mail_read_thread's numbering. This adds substantial meaning beyond the schema's bare types.
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 clearly states the tool's output format ('One line per message: index, date, size, from, and a marker when the subject changes') and identifies the resource as a mail thread overview. It distinguishes itself from sibling mail_read_thread by emphasizing its lightweight, token-efficient nature.
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?
Explicit guidance is provided: 'Use this before mail_read_thread on any thread you have not looked at yet' and 'Do not use it in place of mail_read_thread when you already know you need the full content.' This clearly states when to use and when not to use, and names the alternative tool.
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. Dates show when Glama detected each change.
12 tool updates
v3.0.0- Changed
mail_count5 fields changed- changed
Input schema / properties / count / titleBefore"count"
After"Count"
- changed
Input schema / properties / query / titleBefore"query"
After"Query"
- added
Input schema / properties / scope / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / scope / titleBefore"scope"
After"Scope"
- removed
Input schema / properties / scope / type"string"
- Changed
mail_find_attachments11 fields changed- added
Input schema / properties / limit / anyOf[ { "type": "integer" }, { "type": "null" } ] - changed
Input schema / properties / limit / defaultBefore50
Afternull
- changed
Input schema / properties / limit / titleBefore"limit"
After"Limit"
- removed
Input schema / properties / limit / type"string"
- changed
Input schema / properties / query / titleBefore"query"
After"Query"
- added
Input schema / properties / scope / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / scope / titleBefore"scope"
After"Scope"
- removed
Input schema / properties / scope / type"string"
- added
Input schema / properties / type / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / type / titleBefore"type"
After"Type"
- removed
Input schema / properties / type / type"string"
- Changed
mail_list_addresses8 fields changed- added
Input schema / properties / limit / anyOf[ { "type": "integer" }, { "type": "null" } ] - changed
Input schema / properties / limit / titleBefore"limit"
After"Limit"
- removed
Input schema / properties / limit / type"string"
- changed
Input schema / properties / output / titleBefore"output"
After"Output"
- changed
Input schema / properties / query / titleBefore"query"
After"Query"
- added
Input schema / properties / scope / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / scope / titleBefore"scope"
After"Scope"
- removed
Input schema / properties / scope / type"string"
- Changed
mail_list_attachments1 field changed- changed
Input schema / properties / message_id / titleBefore"message_id"
After"Message Id"
- Changed
mail_pending11 fields changed- changed
Input schema / properties / direction / titleBefore"direction"
After"Direction"
- added
Input schema / properties / limit / anyOf[ { "type": "integer" }, { "type": "null" } ] - changed
Input schema / properties / limit / defaultBefore50
Afternull
- changed
Input schema / properties / limit / titleBefore"limit"
After"Limit"
- removed
Input schema / properties / limit / type"string"
- added
Input schema / properties / older_than / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / older_than / titleBefore"older_than"
After"Older Than"
- removed
Input schema / properties / older_than / type"string"
- added
Input schema / properties / scope / anyOf[ { "type": "string" }, { "type": "null" } ] - changed
Input schema / properties / scope / titleBefore"scope"
After"Scope"
- removed
Input schema / properties / scope / type"string"
- Changed
mail_prepare_reply4 fields changed- changed
Input schema / properties / message_id / titleBefore"message_id"
After"Message Id"
- changed
Input schema / properties / mode / titleBefore"mode"
After"Mode"
- changed
Input schema / properties / quote / titleBefore"quote"
After"Quote"
- changed
Input schema / properties / quote / typeBefore"string"
After"boolean"
- Changed
mail_read_attachment3 fields changed- changed
Input schema / properties / message_id / titleBefore"message_id"
After"Message Id"
- changed
Input schema / properties / part_index / titleBefore"part_index"
After"Part Index"
- changed
Input schema / properties / part_index / typeBefore"string"
After"integer"
- Added
mail_read_message - Added
mail_read_thread - Changed
mail_related_threads5 fields changed- added
Input schema / properties / limit / anyOf[ { "type": "integer" }, { "type": "null" } ] - changed
Input schema / properties / limit / defaultBefore10
Afternull
- changed
Input schema / properties / limit / titleBefore"limit"
After"Limit"
- removed
Input schema / properties / limit / type"string"
- changed
Input schema / properties / thread_id / titleBefore"thread_id"
After"Thread Id"
- Added
mail_search - Changed
mail_thread_overview2 fields changed- changed
Input schema / properties / layout / titleBefore"layout"
After"Layout"
- changed
Input schema / properties / thread_id / titleBefore"thread_id"
After"Thread Id"
10 tool updates
v1.0.0- First observed
mail_count - First observed
mail_find_attachments - First observed
mail_list_addresses - First observed
mail_list_attachments - First observed
mail_list_scopes - First observed
mail_pending - First observed
mail_prepare_reply - First observed
mail_read_attachment - First observed
mail_related_threads - First observed
mail_thread_overview
TDQS
Each tool targets a distinct operation: search, read single message, read thread, thread overview, related threads, pending, count, address resolution, attachment listing, attachment reading, attachment finding, scope listing, and reply preparation. Overlapping tools like mail_search and mail_count are clearly differentiated by output type.
All tools follow the mail_ prefix with snake_case, and most use a verb_noun structure (read_message, list_addresses, find_attachments). A few deviate slightly (mail_search, mail_pending, mail_related_threads) but the pattern is predictable and consistent in style.
13 tools is well-scoped for a mail search and retrieval server. Each tool serves a clear purpose, and the count neither feels excessive nor sparse. The set covers reading, searching, attachments, addresses, and reply preparation without unnecessary duplication.
The read-side coverage is strong, but there are gaps: mail_list_scopes references a mail_tag tool that is not present, and there is no way to modify tags, send mail, or create drafts within this server. The prepare_reply tool is a read-only dead end without a draft/send tool. These omissions will cause agent failures when trying to complete write operations.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Related MCP Servers
- AlicenseAqualityDmaintenanceLocal MCP server for multi-account IMAP/SMTP email (iCloud + Gmail via app-specific passwords). Never marks mail read. Cross-folder search, idempotent sends, TLS verified.8MIT
- AlicenseNot gradedqualityDmaintenanceEnables LLMs to search and read email from a notmuch archive, providing tools for searching threads, retrieving messages, and listing tags through an MCP endpoint.MIT
- FlicenseNot gradedqualityCmaintenanceLocal IMAP/SMTP MCP server that lets Claude read, search, draft, send, flag, and move mail across multiple IMAP mailboxes. Credentials stay on your machine.-
- AlicenseAqualityCmaintenanceAn MCP server that lets Claude read, search, and send email over standard IMAP/SMTP.6MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/hgn/mcp-server-notmuch'
If you have feedback or need assistance with the MCP directory API, please join our Discord server