dead-letter
dead-letter
.eml 파일에 두 번째 생명을 주세요.
dead-letter는 이메일 내보내기를 YAML front matter가 포함된 깔끔한 Markdown으로 변환합니다. 스레드는 분리되고, 서명은 제거되며, 첨부 파일은 추출되고, 캘린더는 파싱됩니다. 파일 하나든 만 개든 상관없습니다.
✨ 기능
완전 충실도 변환 — HTML 정화, Gmail/Outlook 스레드 분할, 인라인 이미지 처리, 캘린더 이벤트 요약
CLI — 파일이나 디렉터리를 지정하기만 하면 됩니다
로컬 웹 UI — 드래그 앤 드롭 가져오기, watch 모드, 변환 등급 배지, 처리 기록, 작업별 진단을 제공하는 다크 커맨드 센터 인터페이스
Inbox/Cabinet 워크플로 —
.eml파일을 Inbox에 넣으면 dead-letter가 Markdown 번들을 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 헤더, multipart 경계, 중복된 HTML/plain 본문, 인코딩된 첨부 파일이 모두 텍스트 경로에 섞여 들어갑니다.
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 클라이언트가 셸 명령 없이 dead-letter의 변환 도구를 호출할 수 있습니다.
📊 토큰 비용 벤치마크
dead-letter의 가치는 모든 대안보다 토큰이 적다는 것이 아니라 토큰당 충실도(fidelity per token), 즉 이메일을 온전하게 유지하는 가장 저렴한 표현입니다. HTML 스레드, 첨부 파일, 뉴스레터로 구성된 합성 코퍼스에서 측정했습니다(토크나이저 o200k_base, 중앙값):
원시
.eml보다 토큰 약 88% 감소 — PDF 첨부 파일이 있는 이메일 하나는 원시 기준 약 126k 토큰인 반면 변환 시 약 180 토큰입니다.이메일을 온전하게 유지하는 유일한 표현 — 스레드 구조, 메시지별 발신자 표시, 링크, 첨부 파일 메타데이터가 모두 보존됩니다. 단순 텍스트 추출이 더 저렴한 이유는 정확히 이러한 요소를 버리기 때문입니다(첨부 파일 0/2 보존 vs dead-letter의 2/2).
벤치마크는 어디에서 손해를 보는지 정직하게 공개합니다. 첨부 파일, 링크, 스레드 구조를 버려도 괜찮다면 단순 추출이 토큰이 더 적습니다. 전체 방법, 완전한 표(해당 행 포함), 토크나이저 공개, 원커맨드 재현 방법은 benchmarks/에 있습니다.
📦 설치
Apple silicon macOS에서 Homebrew로 설치:
brew tap BigCactusLabs/tap
brew install dead-letterHomebrew 포뮬러는 핵심 CLI만 설치합니다: dead-letter convert 및 dead-letter doctor. 선택적 웹 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 serverUI 또는 MCP를 격리된 환경에 설치하려면 pipx를 사용하세요:
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 파일을 재귀적으로 스캔하고, 접미사를 대소문자 구분 없이 매칭하며, 확인된 대상이 요청된 입력 트리를 벗어나는 심링크 파일을 건너뛰고, 동일한 메시지 파일로 확인되는 트리 내 심링크 별칭을 중복 제거합니다.
웹 UI — 로컬 서버 시작:
dead-letter-ui --host 127.0.0.1 --port 8765http://127.0.0.1:8765을 엽니다. 첫 실행 시 설정 프롬프트가 기본 Inbox 및 Cabinet 폴더를 제안합니다. 구성하거나 건너뛰고 변환을 시작하세요. 드래그 앤 드롭 또는 파일 선택기로 .eml 파일을 가져옵니다. 단일 파일 가져오기는 파일 모드를 사용하고, 다중 파일 드롭은 디렉터리 모드 배치 작업 하나를 생성합니다. 혼합 드롭은 .eml이 아닌 파일을 건너뛰기 전에 확인을 요청합니다. 백엔드는 단일 및 배치 업로드 모두에 파일당 100MB 가져오기 제한을 적용합니다.
소스 체크아웃에서는 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/ 아래에 작성되기 전에 안전한 기본 이름으로 정규화됩니다.
품질 진단에는 보존 대상 첨부 파일이 있는 메시지의 참조/보존 첨부 파일 개수가 포함되므로, 누락된 아티팩트를 기계적으로 감지할 수 있습니다. 품질 진단을 참조하세요.
배치:
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는 LLM 클라이언트가 셸 명령 없이 .eml 파일을 직접 변환할 수 있도록 MCP 서버를 제공합니다.
설치 및 실행:
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 요약. 호출당 |
|
| 품질 및 구조 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도 실행합니다.
📚 문서
🔧 우리가 사랑하는 도구
MarkEdit — Markdown용 TextEdit, 네이티브 macOS, 약 4MB. 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