md_converter_mcp
MCP server for converting Markdown files to print-ready PDF and Word (DOCX) with professional styling, page numbers, table of contents, and custom themes.
Built for local use with Claude Code — your Markdown files never leave your machine and never enter the LLM context window.
Why MCP instead of a script?
When you ask an LLM to convert a Markdown file, it has to:
- Read the entire file into the context window
- Write conversion code
- Execute and debug it
- Return the result
With an MCP server, the LLM just calls a tool with a file path. The heavy lifting happens outside the context window.
Token Usage Benchmark
Tested on a real 1,072-line Markdown file (37 KB, ~10,000 tokens):
| Approach | Input Tokens | Output Tokens | Total | Cost (Opus) | |----------|-------------|---------------|-------|-------------| | MCP tool call | ~100 | ~50 | ~150 | ~$0.003 | | LLM reads file + generates code | ~12,000 | ~2,000 | ~14,000 | ~$0.27 |
MCP is ~93x cheaper per conversion.
For a batch of 10 similar files:
| Approach | Total Tokens | Cost (Opus) | |----------|-------------|-------------| | MCP batch tool | ~500 | ~$0.01 | | LLM manual approach | ~100,000+ | ~$2.00+ |
MCP is ~200x cheaper at batch scale because file contents never enter the context window.
Note: "LLM manual approach" estimates include reading files, writing/debugging conversion scripts, and processing output. Actual usage varies by model and conversation length.
Features
- PDF output via WeasyPrint with full CSS3 print support
- DOCX output via pandoc with reference document templates
- 3 built-in themes: default (professional sans-serif), academic (serif, formal), minimal (clean whitespace)
- Print-ready: page numbers, headers/footers, TOC generation, custom margins, page size selection
- Syntax highlighting: 500+ languages via Pygments
- Batch conversion: convert entire directories with glob patterns
- Custom themes: bring your own CSS or DOCX template
Installation
Prerequisites
# macOS
brew install pango pandoc
# Ubuntu/Debian
sudo apt install libpango-1.0-0 libpangocairo-1.0-0 pandoc
# Arch
sudo pacman -S pango pandoc
Install the server
git clone https://github.com/YOUR_USERNAME/md_converter_mcp.git
cd md_converter_mcp
uv sync --python 3.12
Generate the default DOCX template:
uv run python -m md_converter_mcp.create_default_template
Configure Claude Code
Add to ~/.claude/settings.json:
{
"mcpServers": {
"md_converter_mcp": {
"command": "/absolute/path/to/md_converter_mcp/.venv/bin/python",
"args": ["-m", "md_converter_mcp.server"]
}
}
}
Or with uv:
{
"mcpServers": {
"md_converter_mcp": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/md_converter_mcp", "md-converter-mcp"]
}
}
}
Usage
In Claude Code (natural language)
Convert /path/to/notes.md to PDF with the academic theme
Batch convert all markdown files in /path/to/docs/ to both PDF and DOCX with TOC
Make a PDF from my-file.md with A4 pages, 25mm margins, and page numbers
Available Tools
md_converter_to_pdf
Convert a single Markdown file to PDF.
| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | input_path | string | required | Absolute path to .md file | | output_path | string | input + .pdf | Output file path | | theme | string | "default" | Theme name or path to .css | | page_size | string | "A4" | A4, Letter, A3, Legal | | margin_mm | int | 20 | Margins in mm (5-50) | | include_toc | bool | false | Generate table of contents | | header_text | string | null | Header with {title}, {date} placeholders | | footer_text | string | "{page} / {pages}" | Footer with page numbering |
md_converter_to_docx
Convert a single Markdown file to Word.
| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | input_path | string | required | Absolute path to .md file | | output_path | string | input + .docx | Output file path | | template | string | "default" | Template name or path to .docx | | include_toc | bool | false | Generate table of contents |
md_converter_batch
Convert multiple files at once.
| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | input_dir | string | required | Directory with .md files | | output_dir | string | input_dir | Output directory | | glob_pattern | string | "*/.md" | File matching pattern | | output_format | string | "pdf" | pdf, docx, or both | | theme | string | "default" | CSS theme (PDF) | | template | string | "default" | DOCX template | | page_size | string | "A4" | Paper size (PDF) | | margin_mm | int | 20 | Margins (PDF) | | include_toc | bool | false | Table of contents | | footer_text | string | "{page} / {pages}" | Footer (PDF) |
md_converter_list_themes
List all available CSS themes and DOCX templates. No parameters.
Themes
Built-in PDF themes
| Theme | Style | Best for | |-------|-------|----------| | default | Professional sans-serif (Inter), clean layout | Business docs, reports, notes | | academic | Serif fonts (Georgia), justified text, formal | Papers, articles, theses | | minimal | Light sans-serif, generous whitespace | Creative writing, simple docs |
Custom themes
Create a CSS file with @page rules and body styling:
@page {
size: {{ page_size }};
margin: {{ margin_mm }}mm;
@bottom-center {
content: {{ footer_content }};
}
}
body {
font-family: "Your Font", sans-serif;
font-size: 11pt;
}
Use it by passing the absolute path:
Convert my-file.md to PDF with theme /path/to/my-theme.css
Or place it in ~/.config/md_converter_mcp/themes/mytheme.css and reference by name:
Convert my-file.md to PDF with theme mytheme
Architecture
Markdown file
|
+---> [markdown-it-py] ---> HTML ---> [WeasyPrint + CSS theme] ---> PDF
|
+---> [pandoc + reference-doc template] ---> DOCX
- PDF path: markdown-it-py parses MD to HTML, Pygments highlights code blocks, WeasyPrint renders with CSS
@pagerules for print layout - DOCX path: pandoc handles everything natively — better DOCX structure than any HTML-to-DOCX approach
- Async: synchronous rendering (WeasyPrint, pandoc) runs in
asyncioexecutor to avoid blocking the MCP event loop
Project Structure
md_converter_mcp/
├── pyproject.toml
├── uv.lock
├── src/
│ └── md_converter_mcp/
│ ├── server.py # FastMCP entry point, 4 tools
│ ├── models.py # Pydantic v2 input models
│ ├── create_default_template.py
│ ├── converter/
│ │ ├── markdown_parser.py # MD -> HTML + Pygments + TOC
│ │ ├── pdf_renderer.py # HTML -> PDF (WeasyPrint)
│ │ ├── docx_renderer.py # MD -> DOCX (pypandoc)
│ │ └── pipeline.py # Single + batch orchestration
│ └── styling/
│ ├── theme_manager.py # Theme/template resolution
│ └── themes/
│ ├── default.css
│ ├── academic.css
│ ├── minimal.css
│ └── default_ref.docx
└── tests/
└── fixtures/
└── sample.md
Tech Stack
| Component | Library | Why | |-----------|---------|-----| | MCP framework | FastMCP (Python SDK) | Best DX, @mcp.tool() decorator | | MD parser | markdown-it-py | Fast, CommonMark compliant | | Syntax highlighting | Pygments | 500+ languages | | PDF renderer | WeasyPrint | Full CSS3 print support, @page rules | | DOCX converter | pypandoc (pandoc) | Native DOCX writer, reference-doc templates | | Input validation | Pydantic v2 | Type-safe tool parameters |
License
MIT











