Skip to main content
Glama
fifeek0

md_converter_mcp

by fifeek0
README.md
# 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](https://docs.anthropic.com/en/docs/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:
1. Read the entire file into the context window
2. Write conversion code
3. Execute and debug it
4. 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

```bash
# 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

```bash
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:

```bash
uv run python -m md_converter_mcp.create_default_template
```

### Configure Claude Code

Add to `~/.claude/settings.json`:

```json
{
  "mcpServers": {
    "md_converter_mcp": {
      "command": "/absolute/path/to/md_converter_mcp/.venv/bin/python",
      "args": ["-m", "md_converter_mcp.server"]
    }
  }
}
```

Or with `uv`:

```json
{
  "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:

```css
@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 `@page` rules 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 `asyncio` executor 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