dead-letter
dead-letter
你的 .eml 文件值得拥有第二次生命。
dead-letter 将电子邮件导出转换为带有 YAML front matter 的干净 Markdown——线程拆分、签名剥离、附件提取、日历解析。一个文件或一万个文件都可以。
✨ 功能特性
全保真转换 — HTML 清理、Gmail/Outlook 线程分段、内联图片处理以及日历事件摘要
CLI — 指向文件或目录即可运行
本地 Web UI — 深色指挥中心界面,支持拖放导入、监视模式、转换等级徽章、处理历史记录和每项任务的诊断信息
Inbox/Cabinet 工作流 — 将
.eml文件放入 Inbox,让 dead-letter 将 Markdown bundle 整理到 Cabinet 中安装验证 —
dead-letter doctor检查你的运行时环境转换报告 — 可选的 JSON 报告,包含每个文件的诊断信息,包括附件引用/保留计数,用于自动化和审计
MCP 服务器 — 与 Claude Desktop、Claude Code、Codex 及其他 MCP 客户端集成
Claude 插件 — 在 Claude Code 或 Cowork 中一键安装,提供四个斜杠命令(
/dead-letter:convert、/dead-letter:summarize、/dead-letter:triage、/dead-letter:cabinet)Python API —
from dead_letter import convert即可开始使用
Related MCP server: DingusMail
🧠 为 LLM 管道而生
原始 .eml 文件对于下游 LLM 和检索管道来说是噪声较大的输入——MIME 头、多部分边界、重复的 HTML/纯文本正文以及编码附件都会混入文本路径中。
dead-letter 将其规范化为带有 YAML front matter 的 Markdown,因此消息文本和元数据无需 MIME 解析或 base64 清理即可用于分块或索引。默认情况下,convert() 和 convert_dir() 运行时会为每条消息写入一个 .md 文件,并将附件名称保留在 front matter 中。
如果你还希望文件系统产物也分离出来,bundle 和 Cabinet 工作流会写入 message.md,并将保留的解码文件放在 attachments/ 下。Markdown 可直接用于文本摄取,而 PDF、电子表格、日历文件和其他保留的二进制附件则被干净地分离出来,供你已有的任何下游解析器使用。
对于直接 LLM 集成,MCP 服务器让 Claude Desktop、Claude Code、Codex 及其他 MCP 客户端无需通过 shell 即可调用 dead-letter 的转换工具。
📊 Token 成本基准
dead-letter 的价值不在于比所有替代方案使用更少的 token——而在于每个 token 的保真度:保持电子邮件完整的最廉价表示。在包含 HTML 线程、附件和新闻通讯的合成语料库上测量(分词器 o200k_base,中位数):
比原始
.eml减少约 88% 的 token — 一封带 PDF 附件的电子邮件原始约 126k token,转换后约 180。唯一能保持电子邮件完整的表示 — 线程结构、每条消息的发件人归属、链接和附件元数据都得以保留。朴素文本提取之所以更便宜,恰恰是因为它丢弃了这些内容(保留 0/2 个附件,而 dead-letter 保留 2/2 个)。
基准测试诚实地说明了它在哪些方面会逊色:如果你不介意丢弃附件、链接和线程结构,朴素提取的 token 更少。完整方法、完整表格(包括这些行)、分词器说明以及一条命令即可复现,均见 benchmarks/。
📦 安装
在 Apple 芯片 macOS 上使用 Homebrew:
brew tap BigCactusLabs/tap
brew install dead-letterHomebrew formula 仅安装核心 CLI:dead-letter convert 和 dead-letter doctor。它有意不捆绑可选的 Web UI 或 MCP 服务器依赖栈。
使用 pip:
pip install dead-letter # core + CLI
pip install dead-letter[cli] # + watchfiles (used by backend/UI watch mode)
pip install dead-letter[ui] # + web UI, API server, and watch mode
pip install dead-letter[mcp] # + MCP server使用 pipx 进行隔离的 UI 或 MCP 安装:
pipx install 'dead-letter[ui]' # installs dead-letter and dead-letter-ui
pipx install 'dead-letter[mcp]' # installs dead-letter and dead-letter-mcp从源码安装:
git clone https://github.com/BigCactusLabs/dead-letter.git
cd dead-letter
uv sync --extra dev # all extras
uv sync --extra ui # UI only
uv sync --extra mcp # MCP only🚀 快速开始
CLI — 转换单个文件:
dead-letter convert message.eml转换整个目录:
dead-letter convert inbox/ --output out/在输出旁边生成 JSON 转换报告:
dead-letter convert inbox/ --output out/ --report使用 --output 时,报告会以 .dead-letter-report.json 的形式写入该输出目录。不使用 --output 时,文件转换会将报告写在源消息旁边,目录转换则将其写入输入目录根目录。
检查你的运行时环境:
dead-letter doctor目录转换会递归扫描 .eml 文件,不区分大小写地匹配后缀,跳过解析目标超出所请求输入树的符号链接文件,并去重解析到同一消息文件的树内符号链接别名。
Web UI — 启动本地服务器:
dead-letter-ui --host 127.0.0.1 --port 8765打开 http://127.0.0.1:8765 — 首次启动时,设置提示会建议默认的 Inbox 和 Cabinet 文件夹。配置或跳过即可开始转换。通过拖放或文件选择器导入 .eml 文件。单文件导入使用文件模式,而多文件拖放会创建一个目录模式的批处理任务。混合拖放会在跳过非 .eml 文件前要求确认。后端对单个和批量上传均强制执行每个文件 100 MB 的导入限制。
从源码检出目录运行时,加上 uv run 前缀:
uv run dead-letter convert message.eml
uv run --extra ui dead-letter-ui --host 127.0.0.1 --port 8765🐍 Python API
from dead_letter import convert
result = convert("message.eml")
print(result.subject, result.sender)
print(result.output) # path to the generated .md使用选项:
from dead_letter import convert, ConvertOptions
result = convert("message.eml", options=ConvertOptions(
strip_signatures=True,
strip_quoted_headers=True,
))去除签名图片(徽标、社交图标)和跟踪像素:
result = convert("message.eml", options=ConvertOptions(
strip_signature_images=True,
strip_tracking_pixels=True,
))启用后,这些过滤器会从渲染的 Markdown 中移除匹配的图片,并从 bundle 附件输出中省略被剥离的内联签名/跟踪资源。
Bundle 转换(Markdown + 附件 + 源文件位于同一目录):
from dead_letter import convert_to_bundle
bundle = convert_to_bundle("message.eml", bundle_root="cabinet/", source_handling="copy")
print(bundle.markdown) # cabinet/message/message.md
print(bundle.attachments) # retained extracted files under cabinet/message/attachments/source_handling="copy" 会将原始 .eml 保留在原处。如果省略,convert_to_bundle() 默认使用 source_handling="move",并将源消息移入 bundle。
保留的提取附件文件名在写入 attachments/ 之前会被规范化为安全的基名。
当消息包含符合保留条件的附件时,质量诊断会包含引用/保留附件计数,因此被丢弃的产物可以被机器检测到。参见 Quality Diagnostics。
批量处理:
from dead_letter import convert_dir
for r in convert_dir("inbox/", output="out/"):
print(f"{'✓' if r.success else '✗'} {r.source.name}")🔌 MCP 服务器
dead-letter 附带一个 MCP 服务器,使 LLM 客户端无需通过 shell 即可直接转换 .eml 文件。
安装并启动:
pip install dead-letter[mcp]
dead-letter-mcp从源码检出目录:
uv run --extra mcp dead-letter-mcpClaude Desktop — 添加到 claude_desktop_config.json:
{
"mcpServers": {
"dead-letter": {
"command": "uv",
"args": ["--directory", "/path/to/dead-letter", "run", "--extra", "mcp", "dead-letter-mcp"]
}
}
}Claude Code 或 Cowork(推荐 — Claude 插件):
/plugin marketplace add BigCactusLabs/bigcactuslabs-plugins
/plugin install dead-letter该插件捆绑了 MCP 服务器(通过 uvx,无需 pip install — 只需 PATH 上有 uv),并添加了四个斜杠命令:/dead-letter:convert、/dead-letter:summarize、/dead-letter:triage、/dead-letter:cabinet。通过插件处理的电子邮件内容被视为不可信数据而非指令,因此消息中嵌入的工具使用、凭据和泄露请求不会被遵循。源码位于 plugin/。
插件市场会固定每个已发布插件标签和提交。发布自动化仅在捆绑的 MCP 服务器的确切 PyPI 版本上线后才更新该指针,因此 Claude Code 和 Cowork 解析到的是相同的可重现版本。
Claude Code(手动添加 MCP — 替代方案):
claude mcp add dead-letter -- uv run --extra mcp dead-letter-mcpCodex:
codex mcp add dead-letter -- uv run --extra mcp dead-letter-mcp
codex mcp listcodex mcp add 命令会注册本地的 dead-letter MCP 服务器,codex mcp list 可验证它是否可用。
工具
工具 | 必需参数 | 返回值 |
|
| Markdown 文本。当指定 |
|
| 包含 |
|
| JSON 摘要。每次调用最多处理 50 个 |
|
| 质量和结构 JSON。不写入任何永久内容。 |
这四个工具都接受 preset(default、clean、verbose、raw)和逐标志覆盖。完整契约(包括仅限 MCP 的约束和错误文本表):docs/reference/v4-runtime-contracts.md。
🗂 项目结构
src/dead_letter/
├── core/ # conversion pipeline (MIME, HTML, threads, rendering)
├── backend/ # CLI, API server, job runner, watch mode, MCP server
└── frontend/ # static web UI (Alpine.js ES modules + vanilla fetch)
tests/
├── core/ # conversion pipeline tests with .eml fixtures
├── backend/ # API, job, and watch tests
├── plugin/ # Claude plugin manifest, skill, and command tests
└── frontend/ # JS unit tests🧪 测试
uv run pytest -q tests/core # conversion pipeline
uv run pytest -q tests/backend # API and job runner
uv run pytest -q tests/plugin # Claude plugin manifest, skill, and command surfaces
node --test tests/frontend/*.test.js # frontendCI 在 PR 以及推送到 main 或 feat/** 分支时使用相同命令运行全部四项测试,另外还会运行 npx --yes @anthropic-ai/claude-code@2.1.145 plugin validate plugin/ 和 node --check src/dead_letter/frontend/static/app.js。
📚 文档
Docs Index — 公共文档着陆页
Runtime Contracts — 完整 API 和核心行为规范
Agent Guide — 面向在此仓库中工作的 AI 编码代理的操作指南
🔧 我们喜爱的工具
MarkEdit — Markdown 版 TextEdit,原生 macOS,约 4 MB。打开 dead-letter 的输出,就像它天生就该放在那里一样。
mo — 本地 Markdown 查看器,在浏览器中渲染文件并支持实时重载。将其指向你的 Cabinet,像阅读信息流一样阅读转换后的邮件。
⚠️ 已知限制
仅限本地 — 无远程服务器,无身份验证
内存中的任务注册表(重启后状态重置)
单用户、单机
许可证
PolyForm Noncommercial 1.0.0 — 免费用于个人、教育和非营利用途。商业使用需要从 Big Cactus Labs 获取单独的许可证。
Available Tools
5 toolsconvert_directoryConvert email folderA
Batch convert all .eml files in a directory to Markdown.
Recursively finds .eml files (at most 50 per call; larger directories are rejected before any conversion). output_directory is required: Markdown is written there, mirroring subfolders, and source .eml files are left in place. Returns a JSON summary with total, successes, failures, output_paths, and errors. Each errors entry contains file and error_code (defaulting to conversion_error), never raw exception text.
Use convert_eml to retrieve individual converted file content.
| Name | Required | Description | Default |
|---|---|---|---|
| preset | No | default | |
| dry_run | No | ||
| directory | Yes | ||
| thread_mode | No | latest | |
| thread_order | No | oldest-first | |
| include_raw_html | No | ||
| output_directory | Yes | ||
| strip_signatures | No | ||
| strip_disclaimers | No | ||
| embed_inline_images | No | ||
| include_all_headers | No | ||
| no_calendar_summary | No | ||
| strip_quoted_headers | No | ||
| strip_tracking_pixels | No | ||
| strip_signature_images | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: the 50-file cap with pre-conversion rejection, that source .eml files are left in place, that subfolders are mirrored into output_directory, and that errors carry a file plus a sanitized error_code rather than raw exception text. That is exactly the operational context an agent needs before spending a large batch run.
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-loads the core action, then constraints, then output contract, then the sibling pointer — each sentence carries distinct information with no filler. Length is proportionate to a 15-parameter batch tool.
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 output schema exists, and the description still usefully summarizes the JSON summary shape, so return values are covered. However, for a tool with 15 options and an enum-based preset system, the complete absence of guidance on how the conversion options interact (preset vs individual strip_* flags) leaves a real gap.
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% across 15 parameters, so the description carries the full burden — but it only explains output_directory (required, receives Markdown, mirrors subfolders). The 12 conversion flags and 3 enums (preset, thread_mode, thread_order) are entirely undocumented, so an agent cannot tell what 'clean' vs 'verbose' preset or 'structured' thread_mode does.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource: 'Batch convert all .eml files in a directory to Markdown,' which immediately separates it from the single-file convert_eml. It does not explicitly contrast with convert_mbox or convert_eml_to_bundle, so sibling differentiation is only partial.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete usage context (recursive .eml discovery, hard cap of 50 files with upfront rejection) and routes the agent to convert_eml for reading back individual converted content. It stops short of stating when-not to use it, e.g. for mbox archives, which is left to inference from sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
convert_emlConvert emailA
Convert a .eml email file to Markdown with YAML front matter.
Returns the full Markdown content (front matter + body). When output_path is provided, also writes the file to disk.
Attachments are listed in the front matter but not written to disk; use convert_eml_to_bundle to save the decoded attachment files.
thread_mode="structured" adds a section per earlier reply or forwarded message. Gmail HTML forwards and unquoted plain-text forwards are kept in latest mode too; a plain-text forward inside ">" quoting is not.
Presets bundle common flag combinations:
default: strips signatures, tracking pixels, signature images
clean: default + strips disclaimers and quoted headers
verbose: includes all headers and raw HTML
raw: no stripping, preserves everything
Individual flags override the preset when provided.
| Name | Required | Description | Default |
|---|---|---|---|
| preset | No | default | |
| eml_path | Yes | ||
| output_path | No | ||
| thread_mode | No | latest | |
| thread_order | No | oldest-first | |
| include_raw_html | No | ||
| strip_signatures | No | ||
| strip_disclaimers | No | ||
| embed_inline_images | No | ||
| include_all_headers | No | ||
| no_calendar_summary | No | ||
| strip_quoted_headers | No | ||
| strip_tracking_pixels | No | ||
| strip_signature_images | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the file-writing side effect of output_path, that attachments are listed but not written, the per-preset stripping behavior, and that individual flags override presets. The described write behavior is consistent with readOnlyHint=false and destructiveHint=false.
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 primary behavior, then organized into short paragraphs and a bulleted preset list that is genuinely useful given the empty schema descriptions. Slightly verbose on the forward-quoting edge case, but nothing extraneous.
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?
Covers the entity, the output shape, the disk side effect, and the preset/flag interaction, and an output schema exists so return-value detail is not owed. The remaining gap is semantics for the unlisted boolean flags in a 14-parameter 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 carries the param burden and it partially does: all four preset values and both thread_mode values are given meaning, and output_path behavior is stated. However, thread_order, no_calendar_summary, embed_inline_images, and several strip_* flags are never characterized, leaving half the surface to title-only inference.
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 plus the exact output format ('Convert a .eml email file to Markdown with YAML front matter'). It also names the sibling convert_eml_to_bundle and the distinct condition that selects it, so an agent can separate the two without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes attachment-saving use cases to convert_eml_to_bundle and explains the thread_mode and preset choices in operational terms. It does not address when convert_directory or convert_mbox should be preferred over this single-file tool, leaving the batch-vs-single decision implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
convert_eml_to_bundleConvert email to bundleA
Convert a .eml file to a self-contained bundle with markdown and attachments.
Creates a directory containing the converted markdown, extracted attachments, and optionally the original .eml source.
source_handling only accepts 'copy' over MCP: the original .eml is copied into the bundle and left untouched. The 'move' and 'delete' modes are rejected here — use the CLI or the Python API for those.
Returns JSON with bundle_path, markdown_path, attachment_paths, and optional diagnostics.
| Name | Required | Description | Default |
|---|---|---|---|
| preset | No | default | |
| eml_path | Yes | ||
| bundle_root | Yes | ||
| thread_mode | No | latest | |
| thread_order | No | oldest-first | |
| source_handling | No | copy | |
| include_raw_html | No | ||
| strip_signatures | No | ||
| strip_disclaimers | No | ||
| embed_inline_images | No | ||
| include_all_headers | No | ||
| no_calendar_summary | No | ||
| strip_quoted_headers | No | ||
| strip_tracking_pixels | No | ||
| strip_signature_images | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=false and readOnlyHint=false, and the description usefully adds that the original .eml is copied and left untouched, plus that unsupported modes are rejected rather than silently downgraded. It lists the returned fields, giving concrete expectations. No contradiction with annotations; only missing detail is failure behavior (e.g., existing bundle directory).
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 output artifact is described first, then the source_handling caveat, then the return shape — a sensible front-loaded order. Paragraph breaks are used well. Minor redundancy: the return JSON is listed despite an output schema existing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the return-value recap is not strictly needed, and the description covers artifact creation and the source-preservation contract. But with 15 parameters at 0% schema coverage and no mention of the preset/thread options that materially change output, an agent cannot choose parameters confidently from this definition alone.
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% across 15 parameters, and the description documents only source_handling. The four enums (preset, thread_mode, thread_order, source_handling) and the ten boolean knobs (strip_signatures, embed_inline_images, include_all_headers, etc.) are left entirely to name inference, so the description does not compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource — convert a .eml file into a self-contained bundle of markdown plus extracted attachments — and clarifies what the output artifact is. It does not explicitly distinguish itself from sibling convert_eml, so the caller must infer the difference from the 'bundle' vs. single-conversion wording.
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 clearly states the MCP-level constraint: source_handling only accepts 'copy' here, and 'move'/'delete' must go through the CLI or Python API. That is a genuine when/when-not statement. It stops short of routing between this tool and convert_eml/convert_directory/convert_mbox, which is the remaining gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
convert_mboxConvert MBOX archiveA
Convert one flat .mbox archive (e.g. Gmail Takeout) to Markdown files.
Bounded: the archive must be at most 256 MiB, and conversion stops after 1000 messages (the response then has truncated=true; use the dead-letter CLI for larger archives). Compressed archives and Apple Mail .mbox directories are rejected. output_directory is required; one .md per message (or one bundle directory when bundles=true) is written there with a collision-safe JSON report. The source archive is never modified.
Returns a JSON summary (processed, converted, skipped, failed, truncated, report_path, and at most 20 failure entries), never message content. Cancellation is not supported; byte/message caps are not a time limit.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| preset | No | default | |
| bundles | No | ||
| dry_run | No | ||
| thread_mode | No | latest | |
| thread_order | No | oldest-first | |
| include_raw_html | No | ||
| output_directory | Yes | ||
| strip_signatures | No | ||
| strip_disclaimers | No | ||
| embed_inline_images | No | ||
| include_all_headers | No | ||
| no_calendar_summary | No | ||
| strip_quoted_headers | No | ||
| strip_tracking_pixels | No | ||
| strip_signature_images | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond annotations: hard 256 MiB and 1000-message caps, the truncated=true signal, the requirement that output_directory be supplied, one .md per message vs bundle directories, a collision-safe report, and the guarantee that the source archive is never modified. It also clarifies negative behavior (no cancellation, caps are not a time limit), which is exactly the kind of trap an agent would otherwise fall into.
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-loads the core purpose in the first sentence, then groups constraints, output behavior, and return shape into short paragraphs. Dense but every sentence carries information an agent needs; no filler or restatement of the 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?
Limits, rejection cases, side effects, and return shape are all covered, and an output schema exists so return values need no further explanation. The gap is the undocumented parameter surface: an agent can call this correctly with defaults, but cannot make informed use of the 14 optional formatting toggles.
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% across 16 parameters, so the description carries the full burden, yet it only touches output_directory (already marked required in schema) and bundles=true. Fourteen parameters — preset, dry_run, thread_mode, thread_order, include_raw_html, embed_inline_images, no_calendar_summary, and all the strip_* toggles — get no explanation of what they change or when to set them.
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 ('Convert one flat .mbox archive ... to Markdown files') with its scope ('one flat', example Gmail Takeout). The distinction from siblings is implicit but strong: convert_directory handles directories, which the description explicitly rejects, and the format (.mbox vs .eml) separates it from convert_eml.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not conditions (compressed archives and Apple Mail .mbox directories are rejected) and a named alternative for out-of-scope work ('use the dead-letter CLI for larger archives'). It does not explicitly route between convert_eml/convert_directory, but the input-format constraint makes the choice unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_diagnosticsGet conversion diagnosticsARead-only
Inspect email quality and structure without writing permanent files.
Use this to assess conversion quality before committing, or to troubleshoot problematic .eml files.
Always returns JSON with: state (normal/degraded/review_recommended), selected_body, segmentation_path, client_hint, confidence, fallback_used, and warnings. Two keys are conditional: stripped_images appears only when images were removed, and attachments only when the message had attachments eligible for retention.
| Name | Required | Description | Default |
|---|---|---|---|
| preset | No | default | |
| eml_path | Yes | ||
| thread_mode | No | latest | |
| thread_order | No | oldest-first | |
| include_raw_html | No | ||
| strip_signatures | No | ||
| strip_disclaimers | No | ||
| embed_inline_images | No | ||
| include_all_headers | No | ||
| no_calendar_summary | No | ||
| strip_quoted_headers | No | ||
| strip_tracking_pixels | No | ||
| strip_signature_images | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Consistent with readOnlyHint=true and openWorldHint=false, and adds value beyond them by stating no permanent files are written and enumerating the return-state vocabulary (normal/degraded/review_recommended) plus conditional keys. Falls short of disclosing limits, cost, or when 'degraded' should trigger a re-run.
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 purpose, then usage, then return contract; no filler. The long enumeration of return keys is slightly heavy given an output schema exists, but it is organized and readable.
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?
Return values are well covered even though an output schema exists, and safety context is adequate. However, for a tool with 13 parameters and zero schema descriptions, omitting any parameter guidance leaves a genuine gap an agent would hit when deciding preset/thread/strip behavior.
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?
Thirteen parameters with 0% schema description coverage, and the description explains none of them — preset, thread_mode, thread_order, and the eight strip_*/include_* flags are opaque. The only indirect hint is stripped_images appearing conditionally when images were removed, which barely signals the stripping flags.
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 ('Inspect email quality and structure') and differentiates from the convert_* siblings by noting it does not write permanent files. A clear read-only inspection tool, though it doesn't name the siblings 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?
Gives two concrete situations: assess conversion quality before committing, or troubleshoot problematic .eml files. This implicitly routes agents away from convert_eml when they only want inspection, but no alternative is named outright.
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.
2 tool updates
v0.4.5- Changed
convert_directory4 fields changed- removed
Input schema / properties / output_directory / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / output_directory / defaultRemoved value: -null - added
Input schema / properties / output_directory / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "directory" -]New value: +[ + "directory", + "output_directory" +]
- Added
convert_mbox
4 tool updates
v0.2.4- First observed
convert_directory - First observed
convert_eml - First observed
convert_eml_to_bundle - First observed
get_diagnostics
TDQS
Scored across 5 tools
convert_eml and convert_eml_to_bundle are closely related but differentiated by bundle/attachment output, while convert_directory and convert_mbox are separated by input type. get_diagnostics is clearly distinct, leaving only minor ambiguity between single-file conversion variants.
All tool names use consistent snake_case and are verb-led, with the convert_* family forming a predictable group and get_diagnostics fitting naturally as a read-only operation. The extra preposition in convert_eml_to_bundle is still clear and consistent.
Five tools form a well-scoped surface for email conversion: single-file, bundle, directory batch, mbox batch, and diagnostics. Each tool has a clear reason to exist without obvious bloat.
The surface covers the core conversion workflows, including attachments via bundles and quality inspection via diagnostics. Minor gaps remain around reading back already-converted outputs, and some archive modes are deliberately rejected and deferred to the CLI/API.
Maintenance
Related MCP Connectors
Document-to-Markdown MCP server — convert PDF, Office and HTML into LLM-ready Markdown.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Hosted MCP server: convert PDFs to clean, LLM-ready Markdown with tables, formulas and OCR.
Document conversion MCP server: PDF to Markdown, image OCR, spreadsheet parsing.
Related MCP Servers
- AlicenseBqualityDmaintenanceA local MCP server that provides LLM clients with read/write access to email and calendar data from Gmail, iCloud, and generic IMAP providers. It runs entirely on your machine, keeping data private while enabling email management, calendar operations, and task handling through natural language.39MIT
- AlicenseAqualityDmaintenanceMCP server for parsing .eml email files, extracting metadata, content, and attachments with smart organization into folders. Enables AI to read and handle email files offline without triggering trackers.22AGPL 3.0
- FlicenseNot gradedqualityCmaintenanceA private, single-user MCP server that unifies Gmail, Microsoft 365/Outlook, and IMAP mailboxes for LLMs to search and read emails live, without storing or caching mailbox contents.-
- AlicenseCqualityDmaintenanceA local-first Python MCP server that turns Gmail, Outlook/Microsoft 365, iCloud Mail, and generic IMAP/SMTP mailboxes into a synchronized, searchable OKF knowledge layer, exposing 38 tools and four resources for mailbox actions, synchronization, retrieval, attachments, and optional semantic search while keeping the provider mailbox authoritative.381MIT