pdf-to-md-mcp-server
# pdf-to-md-mcp-server
MCP server local (stdio) para convertir PDFs a Markdown.
- Extrae texto y estructura (headers, listas, tablas simples) pagina por
pagina con [`pymupdf4llm`](https://pypi.org/project/pymupdf4llm/).
- Las imagenes/diagramas incrustados se guardan en una carpeta
`<nombre>_images/` junto al `.md` y se referencian desde ahi.
- Las paginas sin texto seleccionable (PDFs escaneados) se procesan
automaticamente con OCR ([Tesseract](https://github.com/tesseract-ocr/tesseract),
invocado por PyMuPDF internamente — no hace falta ningun paquete Python de
OCR aparte) pagina por pagina, sin intervencion manual — sirve para
manuales mixtos (algunas paginas con texto real, otras escaneadas).
- Cada pagina queda delimitada por un comentario `<!-- pdf-page: N -->`
(N 1-indexado) para poder ubicar cualquier parte del `.md` en su pagina de
origen del PDF.
- El `.md` arranca con un frontmatter YAML que resume de que trata: `title`
(el que trae el PDF, o si no tiene, el primer H1 detectado en el
contenido), `author`/`subject`/`keywords` si el PDF los trae, `pages`,
`ocr_pages` y `converted_at`. Es metadata estructural (sin LLM) — no un
resumen generado del contenido.
## Requisitos
- Python >= 3.10
- Tesseract instalado en el sistema (el binario, no solo el paquete de
Python), con los idiomas que necesites:
```bash
brew install tesseract tesseract-lang
```
## Instalacion
```bash
cd pdf-to-md-mcp-server
/opt/homebrew/opt/python@3.12/bin/python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
## Tests
```bash
source .venv/bin/activate
pytest
```
Los tests generan PDFs sinteticos (uno con texto real, otro con una pagina
"escaneada") con PyMuPDF y validan que la conversion produzca el `.md`
esperado y dispare el fallback de OCR donde corresponde. Requieren
Tesseract instalado.
## Configuracion (variables de entorno, opcionales)
| Variable | Default | Descripcion |
| ----------------------------- | ---------- | --------------------------------------------------------------- |
| `PDF2MD_OCR_LANG` | `spa+eng` | Idiomas para Tesseract (codigos ISO 639-2 separados por `+`) |
| `PDF2MD_MIN_CHARS_PER_PAGE` | `20` | Umbral de caracteres extraibles por debajo del cual una pagina se reporta como escaneada en `ocr_pages` (informativo — no activa ni evita el OCR en si, que corre pymupdf4llm automaticamente donde haga falta) |
| `PDF2MD_OCR_DPI` | `200` | DPI al renderizar una pagina para pasarla por OCR |
## Ejemplo de `.md` generado
```markdown
---
source_pdf: "manual.pdf"
title: "Manual de usuario"
author: "Acme Corp"
pages: 2
ocr_pages: [2]
converted_at: 2026-09-05T01:18:23+00:00
---
<!-- pdf-page: 1 -->
# Manual de usuario
Seccion 1: Introduccion...
---
<!-- pdf-page: 2 -->
Seccion 2: Instalacion (pagina escaneada, procesada con OCR)...
```
## Tools expuestas
### `convert_pdf_to_markdown(pdf_path, output_dir=None, ocr_lang=None)`
Convierte un PDF puntual. Devuelve `{markdown_path, images_dir, page_count,
ocr_pages}`.
### `convert_pdf_directory(input_dir, output_dir=None, recursive=True, ocr_lang=None)`
Convierte todos los PDF de una carpeta (recursivo por default). Devuelve
`{converted: [...], errors: [...], total_found}` — si un PDF puntual falla,
queda registrado en `errors` y se sigue con el resto.
## Registrar el server en Claude Code
```bash
claude mcp add pdf-to-md -- /ruta/a/pdf-to-md-mcp-server/.venv/bin/python -m src.server
```
(ajusta la ruta al `.venv` real de tu instalacion)
## Registrar el server en Claude Desktop
Agregar en `claude_desktop_config.json`:
```json
{
"mcpServers": {
"pdf-to-md": {
"command": "/ruta/a/pdf-to-md-mcp-server/.venv/bin/python",
"args": ["-m", "src.server"]
}
}
}
```
TDQS
Scored across 2 tools
The two tools are clearly distinct: one converts a single PDF, the other batch-converts all PDFs in a directory. Descriptions reinforce the boundary with separate parameters and return shapes, so there is no realistic confusion.
Both tools share the convert_pdf_ prefix and are readable. The second name is slightly less parallel because it omits the explicit _to_markdown target, but the pattern is still predictable and clear.
With only two tools, the server is minimal but justified for a single-purpose PDF-to-Markdown converter. Each tool earns its place by covering both single-file and batch workflows, so the count is reasonable if slightly on the thin side.
The tool surface fully covers the server's stated purpose: individual conversion, directory batch conversion, recursive traversal, OCR fallback, and error handling. There are no obvious dead ends or missing operations that would block the intended workflow.