Docling-rs MCP
OfficialThe Docling-rs MCP server is a read-only document conversion service for agents.
Convert documents to Markdown with default settings using
convert_to_markdown.Convert to other formats with
convert: docling JSON, HTML, plain text, LaTeX, RAG chunks, WebVTT, or Pandoc JSON.Supply documents as local file paths,
file:URIs,data:URIs, or http(s) URLs when URL fetching is enabled.Use conversion options such as page ranges, OCR language/mode, text-layer-only PDFs, passwords, compact tables, and picture OCR.
Embed images instead of placeholders in Markdown, HTML, or Pandoc output.
List supported input extensions and whether URL fetching is allowed with
list_input_formats.Convert many document types including PDF, Office, HTML, EPUB, email, images, audio, and video transcripts.
Provides a LangChain document loader via the docling-rs[langchain] extra, exposing langchain-docling's DoclingLoader backed by the Rust engine. Documents are converted into structured Markdown/JSON with layout, tables and OCR so they can be fed directly into LangChain pipelines, with a one-import swap from the Python implementation.
Serves as a drop-in replacement for the docling-serve HTTP conversion API, so n8n workflows (alongside other docling-serve clients) can convert PDFs, Office files and other documents to Markdown, JSON and more without changing their configuration.
docling.rs
docling.rs converts documents — PDF, Office, HTML, scans, audio — into Markdown, docling JSON and the other shapes an LLM or a RAG pipeline can read. It is a Rust port of IBM's docling: the same output, byte-for-byte, from one static binary. No Python, no PyTorch.
Pulling text out of a PDF is easy. Keeping its structure — headings in order, tables as tables, scanned pages read — takes layout analysis, table recognition and OCR. docling has the models for that, and a Python stack to match. docling.rs runs the same models from a single binary: PDF 4.3× faster than Python docling at under half the RAM, Office and HTML 20–60× faster, and tables that survive — cell recall 0.94 where MarkItDown gets 0.31 (numbers, method).
Coming from MarkItDown?
pip install docling-rs, swap one import —
from docling_rs.markitdown import MarkItDown — and keep its API, every
format it converts included, with real layout analysis, tables and OCR
behind it: guide,
measured side by side.
Coming from Marker?
pip install docling-rs, swap the imports —
from docling_rs.marker.converters.pdf import PdfConverter — and keep its
API: create_model_dict, text_from_rendered, the JSON block tree, chunks,
marker_single's CLI and output layout, with docling's layout analysis,
TableFormer and OCR behind it and no PyTorch or inference server:
guide, measured side by side.
Coming from MinerU?
pip install docling-rs, swap the imports —
from docling_rs.mineru.parser import parse — and keep MinerU 4's SDK:
ParseResult, markdown(), the Middle JSON, Content Lists and Structured
Content, save()'s layout and mineru-kit parse, with docling's layout
analysis, TableFormer and OCR behind it and no DocVortex or llama.cpp:
guide, measured side by side.
Install
# CLI + models (Linux x64/arm64/s390x + macOS arm64 prebuilt; builds from source elsewhere)
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/install.sh | bash
docling-rs example.pdf # Markdown on stdout
# or from crates.io; --cli puts the models where the installed binary looks
cargo install docling-cli
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/download_dependencies.sh | sh -s -- --cli
pip install docling-rs # Python — drop-in for docling's, MarkItDown's, Marker's and MinerU's APIs
npm install docling.rs # Node.js / Bun
cargo add docling # Rust library
# containers, models baked in (-cuda variants for NVIDIA)
docker run --rm -v "$PWD:/data" ghcr.io/docling-project/docling-rs paper.pdf
docker run -p 127.0.0.1:5001:5001 ghcr.io/docling-project/docling-rs-serveOffice, HTML, Markdown and e-mail need no models. PDF, images and audio need
the ONNX models (layout, OCR, TableFormer, Whisper; under 1 GB): install.sh,
--cli and the containers bring them along; with pip, run
python -c "import docling_rs; docling_rs.download_models()" once; with npm
or a checkout, run download_dependencies.sh where you convert
(details). Windows: docs/WINDOWS.md.
▶ Try it in your browser first — the converter as wasm, OCR included; nothing leaves your device.
Related MCP server: md-server
Use
docling-rs report.pdf > report.md # Markdown (streamed page by page)
docling-rs report.pdf --to json # docling JSON; also html, text, latex, dclx, chunks, images
docling-rs --input ./docs --output ./out # a directory tree; --jobs N in parallel
docling-rs https://example.com/paper.pdf # URLs, data: URIs and stdin (`-`) too
docling-rs https://www.youtube.com/watch?v=ID # a YouTube video: title, description, caption transcript (--to vtt keeps the timing)
docling-rs --help # every flag: OCR, page ranges, images, enrichment, redaction …from docling_rs import DocumentConverter # was: from docling.document_converter import …
doc = DocumentConverter().convert("report.pdf").document
print(doc.export_to_markdown())import { convertFileAsync } from 'docling.rs'
const { content } = await convertFileAsync('report.pdf', { to: 'markdown' })use docling::{DocumentConverter, SourceDocument};
let result = DocumentConverter::new().convert(SourceDocument::from_file("report.pdf")?)?;
println!("{}", result.document.export_to_markdown());curl -F file=@report.pdf 'localhost:5001/v1/convert?to=md' # the server; OpenAPI at /openapi.yamlSame options, same outputs on every surface — every option in
docs/OPTIONS.md.
Highlights
From Python docling:
from docling_rs import DocumentConverter;result.documentis a genuineDoclingDocument(migration notes).Every docling format, and a few it lacks — the table under Status, each validated against live docling (Conformance).
Every output docling has: Markdown (docling's, or a stricter dialect), docling JSON, HTML, plain text, DocLang, LaTeX, Pandoc AST (→ DOCX, EPUB, Typst… through pandoc), WebVTT subtitles, RAG chunks and page images (output formats).
From any language: Rust, Python, Node.js / Bun, the browser (wasm, fully client-side), C, C++, C#, Go, Java and Swift through one C header, any HTTP client, the shell (Integration).
A drop-in server for docling-serve: Open WebUI uses it as its Docling content-extraction engine — point Docling Server URL at
http://<host>:5001— and n8n, Dify and LangChain clients work unchanged (docling-rs serve, Open WebUI setup).AI agents (MCP):
docling-rs mcpgives Claude Desktop, Claude Code, Cursor or VS Code MarkItDown'sconvert_to_markdowntool, plusconvertfor JSON, chunks and the rest —uvx docling-rs-mcp, orclaude mcp add docling -- docling-rs mcp(MCP server).LangChain:
pip install "docling-rs[langchain]"— langchain-docling'sDoclingLoaderon the Rust engine, one import to swap (details).AutoGen:
pip install "docling-rs[autogen]"—DoclingIndexerfills any AutoGen memory with chunks that carry their pages,DoclingConvertToollets an agent read documents (details).Microsoft Agent Framework:
pip install "docling-rs[agent-framework]"— AutoGen's successor:DoclingIndexerfills any Agent Framework vector store,DoclingContextProviderputs the relevant chunks with their pages into each turn (details).Your own formats: register a backend for a format docling.rs does not read — or to read one of its formats your way — from Rust, Python (
@docling_rs.register_backend(extensions=["rtf2"]), and MarkItDown'sregister_converterand plugins) or Node.js, ahead of the built-in formats (pluggable backends).RAG:
docling-rag— chunk, embed and search with a REST API and a web UI (RAG subsystem).Runs where you are: Linux x64 / arm64 / s390x, macOS (Apple Silicon) and Windows prebuilt (CLI, wheels, npm), Intel macs from source, containers for amd64 and arm64; NVIDIA CUDA and TensorRT, DirectML (a prebuilt Windows CLI), CoreML and WebGPU in the browser as opt-in accelerators (GPU, IBM Z).
Developed with Claude Code and TENET (minimalistic AI-driven development framework).
Status
Every format in docling's pipeline converts — plus a few docling lacks. A
file with no or an unknown extension, stdin, an upload or a data: URL is
typed by its content (InputFormat::detect, docling_rs.detect_format,
detectFormat: the packages, the OLE files, PDF, images, audio and video,
iWork, XML, JSON, notebooks, messages, …), and a file that fails under its
extension is checked by content and converted as what it really is, with a
warning.
Category | Formats |
Text & markup | Markdown, AsciiDoc, HTML, MHTML, LaTeX (multi-file arXiv projects, math, tables); plain text and source code ( |
Word processing | DOCX, Word 97–2004 |
Presentations | PPTX, PowerPoint 97–2003, ODP, OpenOffice / StarImpress |
Spreadsheets | XLSX, XLSB, Excel 97–2004, ODS, CSV / TSV, dBase, DIF, SYLK, Lotus 1-2-3, Quattro Pro, MS Works, Kingsoft |
Diagrams · Apple iWork | Visio, SVG, CGM (its text) · Pages, Numbers, Keynote |
PDF & images | PDF (layout, TableFormer, OCR), PNG, JPEG, TIFF, BMP, WebP, GIF, HEIC (opt-in), METS/GBS scans, DjVu |
XML · docling native | JATS, USPTO, XBRL, RIS (Austrian legal XML), DocLang · docling JSON, DocTags, DCLX |
Email · subtitles · mainframe |
|
Audio · video | WAV, MP3, M4A, AAC, OGG, FLAC; MP4, AVI, MOV, MKV, WebM, MPEG — local Whisper or Parakeet, plus scene frames from video; a YouTube watch URL — the video's title, description and caption transcript as timed items ( |
Every extension, with what each backend does:
docs/MIGRATION.md.
Any ffmpeg ≥ 4.x on PATH works; docling.rs shells out to the binary and
parses its output, so no dev headers/libraries are needed.
Debian/Ubuntu:
sudo apt-get install ffmpegFedora:
sudo dnf install ffmpeg-free(orffmpegfrom RPM Fusion)Alpine:
apk add ffmpegmacOS:
brew install ffmpegWindows:
winget install ffmpeg(orchoco install ffmpeg, orscoop install ffmpeg). Installing from a downloaded zip (gyan.dev / BtbN) also works — either add the extractedbin\folder toPATH, or skipPATHentirely and pointDOCLING_FFMPEGat the exe:set DOCLING_FFMPEG=C:\tools\ffmpeg\bin\ffmpeg.exe
Check with ffmpeg -version. DOCLING_FFMPEG overrides the binary used on
any OS; the docling-rs-serve Docker image ships ffmpeg preinstalled.
A trimmed, decode-only build (--disable-everything --enable-…) works too
(#853); docling.rs needs only: the file protocol; the demuxers of your
containers (mov for mp4/mov/m4v, matroska for mkv/webm, avi, mpeg);
the video decoders of your tracks (h264, hevc, vp8, vp9, av1,
mpeg4, mpeg2video, …) with their parsers; the filters select,
metadata, fps, scale, showinfo; the encoders png and
wrapped_avframe; the muxers image2 and null. No audio component is
used — the transcript is decoded in Rust — and the scene scan maps the
video stream alone. Missing a component, ffmpeg fails the scene scan
(Encoder not found, Invalid argument) and the video converts as
transcript only; DOCLING_RS_DEBUG=1 shows the message.
Conformance with Microsoft MarkItDown
MarkItDown converts the same kinds
of documents to Markdown for LLMs. Measured side by side — MarkItDown 0.1.9
(markitdown[all]) and docling.rs master after 2.51.3 (release build), 4 vCPU,
no GPU, 2026-10-25 — on this repository's test corpus and on MarkItDown's own
OCR test set
(scripts/conformance/markitdown_compare.py):
Corpus (files) | MarkItDown, warm | docling.rs, warm | Cold CLI call, MarkItDown / docling.rs | Word F1 | Table-cell recall | Heading recall |
DOCX (38) | 9.32 s | 0.57 s | 1360 / 31 ms | 0.93 / 1.00 | 0.81 / 1.00 | 0.78 / 1.00 |
PPTX (8) | 0.28 s | 0.04 s | 1277 / 11 ms | 0.81 / 0.97 | 0.62 / 1.00 | 0.86 / 1.00 |
XLSX (14) | 2.44 s | 0.30 s | 1472 / 14 ms | 0.60 / 0.95 | 0.78 / 0.98 | — ¹ |
HTML (32) | 0.53 s | 0.05 s | 1248 / 11 ms | 0.98 / 1.00 | 0.88 / 1.00 | 0.96 / 1.00 |
CSV (9) | 0.07 s | 0.01 s | 1250 / 6 ms | 1.00 / 1.00 | 0.78 / 1.00 | — |
EPUB (1) | 0.07 s | 0.02 s | 1473 / 17 ms | 0.99 / 1.00 | — | 1.00 / 1.00 |
PDF (18), full layout + tables + OCR | 19.0 s | 60.3 s | 1442 / 1652 ms | 0.63 / 0.997 | 0.31 / 0.94 | 0.00 / 0.91 |
PDF (18), text layer only ( | 19.0 s | 0.8 s | — | 0.63 / 0.97 | 0.31 / 0.00 | 0.00 / 0.00 |
Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings do not depend on it. Text drawn into
images (MarkItDown's own OCR test set) reads at 1.00 with docling.rs' local
OCR, against 0.00–0.33 for MarkItDown without an LLM. Method, caveats and the full
OCR comparison: docs/MARKITDOWN.md.
Conformance with Marker
Marker (datalab's marker-pdf)
converts PDFs and, through a PDF render, Office files to Markdown for LLMs
with a layout model and OCR. Measured side by side — Marker 2.0.0
(marker-pdf[full], its CPU default fast mode, llama.cpp for its OCR) and
docling.rs master after 2.51.3 (release build), 4 vCPU, no GPU, 2026-10-25 ³ —
on this repository's test corpus
(scripts/conformance/marker_compare.py):
Corpus (files) | Marker, warm | docling.rs, warm | Cold CLI call, Marker / docling.rs | Peak RSS, Marker (client + servers) / docling.rs | Word F1 | Table-cell recall | Heading recall |
PDF (18), full layout + tables + OCR | 1356 s | 64 s | 32.6 s / 1.5 s | 10.3 GB / 2.8 GB | 0.93 / 0.997 | 0.41 / 0.94 | 0.66 / 0.91 |
PDF (18), text layer only ( | 1356 s | 0.75 s | — | — / 74 MB | 0.93 / 0.97 | 0.41 / 0.00 | 0.66 / 0.00 |
DOCX (38) | 707 s (1 failed) | 0.54 s | 36.3 s / 23 ms | 7.7 GB / 41 MB | 0.89 / 1.00 | 0.57 / 1.00 | 0.73 / 1.00 |
PPTX (8) | 4.6 s (3 failed) | 0.03 s | 33.7 s / 13 ms | 2.7 GB / 20 MB | 0.49 / 0.97 | 0.41 / 1.00 | 0.43 / 1.00 |
XLSX (14) | 379 s (2 failed) | 0.33 s | 34.4 s / 12 ms | 17.2 GB / 53 MB | 0.66 / 0.95 | 0.58 / 0.98 | — ¹ |
HTML (32) ³ | 1514 s | 0.06 s | 29 min ² / 8 ms | 8.8 GB / 21 MB | 0.94 / 1.00 | 0.50 / 1.00 | 0.84 / 1.00 |
EPUB (1) | 13.5 s | 0.08 s | 69.9 s / 21 ms | 6.0 GB / 19 MB | 0.98 / 1.00 | — | 1.00 / 1.00 |
A failed file scores 0. ¹ Only one XLSX groundtruth carries a heading.
² The median HTML file needs OCR in Marker: a cold call starts its llama.cpp
server and loads the 1.2 GB OCR model first.
³ The HTML row is the earlier run's (docling.rs 2.46.2, another host): its
re-run here was stopped after 3 h 45 min — its warm pass done, the first cold
marker_single call had spent 97 minutes on one 855-byte file, Marker's OCR model
looping on one render (5,000+ tokens for a single block).
Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings and memory do not depend on it.
Marker reads Office files, HTML and EPUB by rendering them to PDF and
running its vision models on the render; on CPU every page its text check
flags goes through a 1.2 GB vision-language OCR model in a llama.cpp server
that pip install marker-pdf does not bring (without it 4 PDFs, 9 DOCX, 10
HTML and the EPUB fail outright). Peak RSS counts Marker's client and its
inference servers. Marker's balanced mode (its published benchmarks) needs
a GPU. Method, caveats and the API map:
docs/MARKER.md.
Conformance with MinerU
MinerU (OpenDataLab) converts PDFs,
images and Office files to Markdown and JSON for LLMs in four tiers — flash
(text layer, no models), basic (ONNX layout / table / OCR models),
standard and advanced (a vision-language model through llama.cpp).
Measured side by side — MinerU 4.0.12 and docling.rs master after 2.51.3
(release build), 4 vCPU, no GPU, 2026-10-25 — on this repository's test corpus
(scripts/conformance/mineru_compare.py):
Corpus (files) | MinerU | MinerU | docling.rs, warm | Cold CLI call, MinerU | Peak RSS, MinerU | Word F1 ( | Table-cell recall | Heading recall |
PDF (18), full layout + tables + OCR | 38.8 s | 190 s (+ 78 s model load) | 62.7 s | 5.7 s / 11.1 s / 1.7 s | 1.4 GB / 4.4 GB / 2.9 GB | 0.87 / 0.74 / 0.997 | 0.28 / 0.44 / 0.94 | 0.57 / 0.58 / 0.91 |
PDF (18), text layer only ( | 38.8 s | — | 0.82 s | — / — / — | — / — / 73 MB | 0.87 / — / 0.97 | 0.28 / — / 0.00 | 0.57 / — / 0.00 |
DOCX (38) | 4.36 s | flash only | 0.70 s | 3331 ms / — / 23 ms | 164 MB / — / 41 MB | 0.97 / — / 1.00 | 0.82 / — / 1.00 | 0.96 / — / 1.00 |
PPTX (8) | 0.26 s (1 failed) | flash only | 0.02 s | 3340 ms / — / 11 ms | 110 MB / — / 20 MB | 0.79 / — / 0.97 | 0.91 / — / 1.00 | 1.00 / — / 1.00 |
XLSX (14) | 1.00 s | flash only | 0.20 s | 1519 ms / — / 13 ms | 130 MB / — / 55 MB | 0.83 / — / 0.95 | 0.77 / — / 0.98 | — ¹ |
HTML (32) | 1.07 s | flash only | 0.07 s | 3039 ms / — / 9 ms | 141 MB / — / 22 MB | 0.94 / — / 1.00 | 0.80 / — / 1.00 | 0.96 / — / 1.00 |
EPUB (1) | 0.12 s | flash only | 0.03 s | 3144 ms / — / 24 ms | 89 MB / — / 19 MB | 1.00 / 1.00 | — | 1.00 / 1.00 |
A failed file scores 0. ¹ Only one XLSX groundtruth carries a heading.
Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings and memory do not depend on it.
MinerU parses Office files, HTML and EPUB at flash only; basic is its
model tier on CPU; its standard tier (a 1.2 B vision-language model through llama.cpp) took 138 s for one page on a 4 vCPU CPU in the earlier run and is not in the table. Method, caveats and the API map:
docs/MINERU.md.
Conformance with Python docling
Every declarative format is compared against the live library — Markdown
byte for byte, JSON structurally (every key and value but origin/version
and re-encoded image bytes). Latest sweep, docling 2.142.1 with the
docling-core 2.103.1 it locks, over its mirrored test corpus
(scripts/conformance/full_conformance.py; ✅ all = every file matches):
Format | Files | Markdown | JSON | Format | Files | Markdown | JSON |
DOCX | 38 | ✅ all | ✅ all | iWork Pages | 1 | ✅ all | ✅ all |
HTML | 32 | 30 ³ | ✅ all | iWork Keynote | 5 | ✅ all | ✅ all |
PPTX | 8 | 7 ⁶ | 7 ⁶ | EBCDIC | 3 | ✅ all | ✅ all |
XLSX | 14 | 13 ² | 13 ² | JATS | 7 | 4 ⁴ | ✅ all |
ODF | 7 | ✅ all | ✅ all | DocLang | 15 | ✅ all | ✅ all |
CSV | 9 | ✅ all | ✅ all | AsciiDoc | 5 | ✅ all | ✅ all |
Markdown | 11 | ✅ all | 10 ⁵ | USPTO | 9 | ✅ all | ✅ all |
DeepSeek-OCR Markdown | 3 | ✅ all | n/a | EPUB | 1 | ✅ all | ✅ all |
WebVTT | 4 | ✅ all | ✅ all | LaTeX | 8 | ✅ all | 7 ¹ |
Email ( | 2 | ✅ all | ✅ all |
¹ Deliberate: in 1706.03762 a \multirow / \multicolumn cell's row_span / col_span agree with its offsets, where upstream leaves them at 1 (docling#4817's LaTeX rewrite is ported in full, PDF figures rendered at 144 dpi like upstream's).
² xlsx_02_sample_sales_data: 20 date cells print by docling PR #4628's number-format rules (#634), which the released docling does not apply yet.
³ Deliberate: a table inside a list item stays a table after the item (upstream prints its grid right under the item line); two Wikipedia links keep docling-core 2.104's %28/%29 escaping.
⁴ Whitespace only: a one-run footnote prints on its bullet, where docling 2.142 leaves the bullet empty and puts the text on the next line.
⁵ Deliberate: a code span keeps its literal text (&), which upstream decodes when a raw HTML block sends the file through its HTML backend.
⁶ Ahead of the release: pptx_chart's 3-D column chart is read as a bar chart with its data, as docling main reads it since docling#4811 (after 2.142.1).
The residuals, with the exact files: docs/MIGRATION.md.
The PDF/image pipeline is pinned by a deterministic snapshot baseline and
scored against docling's groundtruth in
docs/PDF_CONFORMANCE.md.
Performance
One fixture per format through published Python docling and the Rust release
binary (scripts/test/performance.sh); docling ÷ docling.rs, so bigger means
Rust wins by more. Measured 2026-10-25: docling 2.142.1 (the default PyPI
install, torch included) against docling.rs master after 2.51.3, 4 vCPU, no
GPU.
File | Size | Peak-memory ratio | CPU ratio | Warm-conversion speedup |
| 208 KB | 4.8× less | 0.7× | 11.6× |
| 3.1 MB | 28× less | 1.1× | 12× |
| 240 KB | 33× less | 1.1× | 27× |
| 180 KB | 39× less | 1.2× | 11× |
| 168 KB | 32× less | 0.9× | 11× |
| 80 KB | 36× less | 1.1× | 2.7× |
| 8 KB | 43× less | 1.1× | 2.3× |
| 4 KB | 44× less | 1.3× | 0.4× † |
† A 4 KB CSV converts in microseconds, so Rust's own process startup dominates its number; end to end it is 780× faster.
Declarative formats hold 17–28 MB against docling's 750–780 MB (it imports
torch even for them) and finish 200–890× sooner end to end; the PDF peaks at
0.46 GB against 2.2 GB and converts 19× faster end to end. Where the time
goes, and what was measured not to help:
docs/PDF_CONFORMANCE.md.
Integration — using docling.rs from your language
One engine, several front doors, the same options and outputs everywhere.
You write… | Use | Install |
Rust | the |
|
a shell / CI job | the | release binaries · |
anything that speaks HTTP |
|
|
Node.js / Bun / Electron |
|
|
Python |
|
|
LangChain / LlamaIndex |
|
|
the browser / Tauri / a PWA |
|
|
C, C++, C#, Go, Java, Swift, Zig |
| release archives |
Rust when you're already in Cargo; the CLI for scripts and batch jobs; serve when several services share one warm pipeline; Node / Python in-process; wasm when the document must not leave the user's machine; FFI for anything that can call C.
Rust API
use docling::{DocumentConverter, SourceDocument};
let converter = DocumentConverter::new();
let result = converter.convert(SourceDocument::from_file("input.md")?)?;
println!("{}", result.document.export_to_markdown()); // Markdown
println!("{}", result.document.export_to_json()); // docling DoclingDocument JSONEvery conversion knob is one serializable struct, docling::ConvertOptions,
filled the same way by every surface (docs/OPTIONS.md).
The library guide covers the output formats,
error handling, chunking, image extraction, streaming, OCR, the PDF switches,
the remote VLM pipeline and registering your own backends (#680).
HTTP conversion API — docling-rs serve
docling-serve exposes the converter over
HTTP with one warm PDF/image pipeline shared across requests (repeat PDFs skip
the model load), streamed Markdown, batches, ZIP inputs, async jobs, an
interactive test form at GET / and an OpenAPI 3.1 description at
GET /openapi.yaml. It also serves Python docling-serve's routes, so Open
WebUI, n8n, Dify and LangChain clients work unchanged.
docker run -p 127.0.0.1:5001:5001 ghcr.io/docling-project/docling-rs-serve
curl -F file=@paper.pdf localhost:5001/v1/convert # Markdown
curl -F file=@report.docx 'localhost:5001/v1/convert?to=json' # docling JSON
curl -F file=@a.pdf -F file=@b.docx localhost:5001/v1/convert # a batchRequest options, server flags, async jobs, the docling-serve routes and the
Open WebUI setup: crates/docling-serve/README.md;
containers and sizing: docs/DEPLOYMENT.md.
MCP server — docling-rs mcp
docling-rs mcp is a Model Context Protocol
server in the default docling-rs binary and image. Agents get MarkItDown's
convert_to_markdown(uri) tool — same name and contract, so a
markitdown-mcp setup switches by changing the command — plus
convert(uri, to, options) and list_input_formats().
{
"mcpServers": {
"docling": { "command": "docling-rs", "args": ["mcp", "--root", "/Users/me/Documents"] }
}
}claude mcp add docling -- docling-rs mcp --root ~/Documents # Claude Code
uvx docling-rs-mcp --root ~/Documents # the same server from PyPILocal reads stay under --root; URLs need --allow-url-fetch. Listed in the
official MCP registry
and on Smithery. The PyPI
launcher, Docker, Streamable HTTP (--http), the security model and memory
behaviour:
crates/docling-cli/README.md.
RAG subsystem
crates/docling-rag turns documents into
chunks, embeds them (Ollama, Gemini or a local ONNX model), stores them
(SQLite + sqlite-vec or PostgreSQL + pgvector) and searches them — hybrid,
multi-query and HyDE retrieval, an evaluation harness, a REST API and a
built-in search UI.
In the browser — docling-wasm
The declarative converters and the PDF text layer compile to WebAssembly:
npm i docling.rs-wasm, then convert(bytes, filename, to) runs fully
client-side — no server, a ~3.4 MB gzipped module, optional in-browser OCR.
Details and the demo page: crates/docling-wasm.
Node.js, Python and C
Node.js / Bun —
docling.rson npm, a prebuilt N-API addon: sync and async conversion, streaming, chunking, ZIP batches, a warmPipeline.Python —
docling-rson PyPI (docling-rs-cudafor NVIDIA): docling'sDocumentConverterwith a genuine docling-coreDoclingDocument, MarkItDown's API, and the LangChain, AutoGen and Microsoft Agent Framework integrations.C ABI —
docling-ffi: one library and onedocling.hfor C, C++, C#/.NET, Go, Java, Swift and Zig, prebuilt in every published release.
Deploy in a container
Image | What it is |
the HTTP API, models baked in ( | |
the CLI, entrypoint | |
| the same on CUDA 13 + cuDNN 9 ( |
Compose files (standalone, Caddy TLS, CUDA), environment variables, sizing
and observability: docs/DEPLOYMENT.md.
Getting the ML models
The PDF/image pipeline needs ONNX models — RT-DETR layout, PP-OCR, and
TableFormer — and audio needs Whisper. download_dependencies.sh fetches
them from this repository's
releases into
./.models, where every surface looks (--cli: beside a cargo-installed
binary instead):
scripts/install/download_dependencies.sh # from a checkout
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/download_dependencies.sh | sh # anywhereEvery asset and option (ASR presets, enrichment models, NER for PII
redaction, INT8, fonts), GPU execution providers and the environment
overrides: docs/MODELS.md. IBM Z and other targets
without a prebuilt ONNX Runtime: docs/IBMZ.md.
Contributing
Bug reports and pull requests are welcome — see CONTRIBUTING.md for the build and test commands, the conformance workflow, and the conventions a change is expected to follow.
License
MIT, matching upstream docling.
Available Tools
3 toolsconvertARead-only
Convert a document to a chosen output format, with conversion
options, and return the result as text. to picks the format
(Markdown, docling JSON with structure and page provenance, HTML,
plain text, LaTeX, RAG chunks, WebVTT, Pandoc JSON); images embeds
pictures instead of placeholders; options sets page ranges, OCR
language and mode, text-layer-only PDFs, passwords and the rest.
For plain Markdown with default settings, convert_to_markdown is
the simpler call. Inputs and errors as for convert_to_markdown;
an unknown to, images value or option key is an error that says
what is accepted. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Output format: md (Markdown, the default), json (docling's DoclingDocument: structure, tables and page provenance), html, text, latex, chunks (RAG-ready chunk records as JSON), vtt (WebVTT, for audio/video transcripts) or pandoc (Pandoc's JSON AST). | |
| uri | Yes | The document to read: an http: or https: URL (only when the server allows URL fetching — see list_input_formats), a file: URI, a data: URI, or a file path. Relative paths resolve against the server's root; files outside it are refused. | |
| images | No | Pictures in md, html or pandoc output: placeholder (the default, an `<!-- image -->` marker) or embedded (the image as a data: URI). | |
| options | No | Conversion options, docling.rs's shared set (docs/OPTIONS.md), e.g. {"pages": "1-5"}, {"text_layer_only": true} (digital PDFs, fastest; "auto" = the text layer when it has text, OCR when it has none), {"ocr_lang": "ch"}, {"force_full_page_ocr": true}, {"do_picture_ocr": true} (OCR pictures inside Office files), {"password": "…"}, {"compact_tables": false}. A value may also be given as text ("true", "1.5"), as a form sends it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered; the description adds useful behavior beyond that by specifying that an unknown `to`, `images` value or option key is an error that reports accepted values, and that output comes back as text. It does not address rate limits, size limits, or cost of OCR-heavy conversions, so it stops short of full disclosure.
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 verb and object, then formats, then the sibling routing rule — a sensible order with no filler sentences. Slight redundancy in 'Read-only', which repeats readOnlyHint, and the format list overlaps the `to` schema description.
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 core call shape, error semantics, and cross-references a sibling for shared input rules, which is enough for a converter with no output schema and whose return is plainly text. The open-ended `options` bag is the remaining gap, mitigated by pointing at external documentation rather than enumerating keys inline.
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 coverage is 100%, so all four parameters are already documented, and the description largely restates them (format list, image embedding, page ranges, OCR language/passwords). The one meaningful addition is framing `options` as an open-ended shared set pointing at docs/OPTIONS.md, but the open nested object remains vague about accepted keys.
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 a document to a chosen output format') and enumerates the output formats available via `to`. It explicitly names the sibling `convert_to_markdown` and the condition under which that one is preferred, so an agent can distinguish the two without opening 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?
Provides an explicit routing rule: for plain Markdown with default settings, use `convert_to_markdown`. It also delegates correctly ('Inputs and errors as for `convert_to_markdown`'), so the agent knows where the shared preconditions live rather than re-deriving them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
convert_to_markdownARead-only
Read a document as Markdown, with default settings, and return the
Markdown text. Handles PDF (layout analysis, tables, OCR for scans),
Word, PowerPoint, Excel, HTML, EPUB, e-mail, images, audio and more.
Use this whenever Markdown is all you need. Use convert instead for
another output format (docling JSON, HTML, RAG chunks, …), embedded
images, or options such as a page range, OCR language or password.
Fails with a message when the document is missing, outside the
server's root, of an unsupported type (see list_input_formats), or
a URL while URL fetching is off. Read-only. Same name and contract as
MarkItDown's MCP tool.
| Name | Required | Description | Default |
|---|---|---|---|
| uri | Yes | The document to read: an http: or https: URL (only when the server allows URL fetching — see list_input_formats), a file: URI, a data: URI, or a file path. Relative paths resolve against the server's root; files outside it are refused. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description adds genuine behavioral value by enumerating failure conditions: missing document, path outside the server root, unsupported type, and URL when fetching is disabled. It restates 'Read-only' redundantly but the failure-mode disclosure goes well past the annotations.
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 and routing decision, then adds format coverage and failure modes. Nearly every sentence earns its place, though the trailing MarkItDown provenance note is extra context that does not help an agent decide or call.
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?
Complete for a default-settings reader with one parameter: it names the return type, the supported formats, the sibling alternatives, and the error conditions. No output schema exists and the description adequately conveys what comes back.
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 coverage is 100% and the single `uri` parameter is fully documented in the schema, including the http/file/data/path forms and relative-path resolution. The description mostly restates that contract rather than adding syntax or format detail, so the baseline 3 applies.
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 ('Read a document as Markdown ... return the Markdown text') and immediately distinguishes itself from the sibling by naming `convert` as the tool for non-Markdown output. An agent can tell the two apart without opening either schema.
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 says 'Use this whenever Markdown is all you need' and names the alternative tool `convert` plus the exact conditions that select it (other output formats, embedded images, page range, OCR language, password). This is the when-and-when-not pattern at full strength.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_input_formatsARead-only
List the file extensions this server can convert, one per line, and
whether it accepts http(s) URLs. Takes no arguments and converts
nothing. Call it before convert_to_markdown or convert when
unsure whether a file type is supported, or to learn why a URL was
refused.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is partly covered, but the description adds real value beyond them: it states the tool takes no arguments, performs no conversion, and describes the shape of what comes back ('one per line', URL support flag). It stops short of full detail (no mention of pagination or failure modes), so a 4 rather than 5.
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?
Two tight sentences, zero waste. The output content is stated first, then the negative scoping ('converts nothing'), then the routing advice – well front-loaded.
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?
No output schema exists, so the description carries the burden of describing returns, and it does: extensions listed one per line plus URL acceptance. For a zero-argument, read-only discovery tool this is complete.
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?
Zero parameters, which sets the baseline at 4. The description reinforces this by explicitly saying it takes no arguments, so there is nothing further the schema could add.
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 (list the file extensions the server can convert) plus a secondary fact it returns (whether http(s) URLs are accepted). It also explicitly distinguishes itself from the convert siblings by noting it 'converts nothing', so an agent can tell the tools apart without opening any schema.
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?
Names both alternatives (`convert_to_markdown`, `convert`) and the exact condition that selects this tool: call it first when unsure whether a file type is supported, or to diagnose a refused URL. Nothing is left to inference.
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.
1 tool update
v2.46.1- Changed
convert1 field changed- changed
Input schema / properties / options / descriptionPrevious value: -"Conversion options, docling.rs's shared set (docs/OPTIONS.md), e.g.\n{\"pages\": \"1-5\"}, {\"text_layer_only\": true} (digital PDFs, fastest),\n{\"ocr_lang\": \"ch\"}, {\"force_full_page_ocr\": true},\n{\"do_picture_ocr\": true} (OCR pictures inside Office files),\n{\"password\": \"…\"}, {\"compact_tables\": false}. A value may also be\ngiven as text (\"true\", \"1.5\"), as a form sends it."New value: +"Conversion options, docling.rs's shared set (docs/OPTIONS.md), e.g.\n{\"pages\": \"1-5\"}, {\"text_layer_only\": true} (digital PDFs, fastest;\n\"auto\" = the text layer when it has text, OCR when it has none),\n{\"ocr_lang\": \"ch\"}, {\"force_full_page_ocr\": true},\n{\"do_picture_ocr\": true} (OCR pictures inside Office files),\n{\"password\": \"…\"}, {\"compact_tables\": false}. A value may also be\ngiven as text (\"true\", \"1.5\"), as a form sends it."
2 tool updates
v2.46.0- Changed
convert3 fields changed- changed
Input schema / properties / images / descriptionPrevious value: -"Pictures in md/html/pandoc output: placeholder (default) or\nembedded (data: URIs)."New value: +"Pictures in md, html or pandoc output: placeholder (the default, an\n`<!-- image -->` marker) or embedded (the image as a data: URI)." - changed
Input schema / properties / to / descriptionPrevious value: -"Output format: md (default), json (docling's DoclingDocument),\nhtml, text, latex, chunks (RAG chunk records as JSON), vtt, pandoc\n(Pandoc's JSON AST)."New value: +"Output format: md (Markdown, the default), json (docling's\nDoclingDocument: structure, tables and page provenance), html, text,\nlatex, chunks (RAG-ready chunk records as JSON), vtt (WebVTT, for\naudio/video transcripts) or pandoc (Pandoc's JSON AST)." - changed
Input schema / properties / uri / descriptionPrevious value: -"The document: an http: or https: URL, a file: URI, a data: URI, or\na path (relative paths resolve against the server's root)."New value: +"The document to read: an http: or https: URL (only when the server\nallows URL fetching — see list_input_formats), a file: URI, a data:\nURI, or a file path. Relative paths resolve against the server's\nroot; files outside it are refused."
- Changed
convert_to_markdown1 field changed- changed
Input schema / properties / uri / descriptionPrevious value: -"The document: an http: or https: URL, a file: URI, a data: URI, or\na path (relative paths resolve against the server's root)."New value: +"The document to read: an http: or https: URL (only when the server\nallows URL fetching — see list_input_formats), a file: URI, a data:\nURI, or a file path. Relative paths resolve against the server's\nroot; files outside it are refused."
1 tool update
v2.31.0- Changed
convert1 field changed- changed
Input schema / properties / options / descriptionPrevious value: -"Conversion options, docling.rs's shared set (docs/OPTIONS.md), e.g.\n{\"pages\": \"1-5\"}, {\"text_layer_only\": true} (digital PDFs, fastest),\n{\"ocr_lang\": \"ch\"}, {\"force_full_page_ocr\": true},\n{\"do_picture_ocr\": true} (OCR pictures inside Office files),\n{\"password\": \"…\"}, {\"compact_tables\": false}."New value: +"Conversion options, docling.rs's shared set (docs/OPTIONS.md), e.g.\n{\"pages\": \"1-5\"}, {\"text_layer_only\": true} (digital PDFs, fastest),\n{\"ocr_lang\": \"ch\"}, {\"force_full_page_ocr\": true},\n{\"do_picture_ocr\": true} (OCR pictures inside Office files),\n{\"password\": \"…\"}, {\"compact_tables\": false}. A value may also be\ngiven as text (\"true\", \"1.5\"), as a form sends it."
3 tool updates
v0.1.0- First observed
convert - First observed
convert_to_markdown - First observed
list_input_formats
TDQS
Scored across 3 tools
convert and convert_to_markdown overlap because convert can also produce Markdown, but the descriptions clearly position convert_to_markdown as the simple default and convert as the option-rich general path. list_input_formats has a clearly distinct discovery role.
Names are consistently snake_case and mostly verb_noun (convert_to_markdown, list_input_formats). The bare verb 'convert' is a minor deviation but still readable and predictable in context.
Three tools are well scoped for a focused document-conversion server: one generic converter, one Markdown convenience path, and one capability-discovery tool. Each earns its place without bloat.
The surface covers the core conversion workflow across many formats, including options, error behavior, and supported-format discovery. A minor gap is the lack of explicit batch conversion or output-to-file operations, though returning text is a workable contract.
Maintenance
Related MCP Connectors
Converts PDF, scans, DOCX, XLSX and PPTX to Markdown with tables and page-aware RAG chunks.
Convert PDF, Word, Excel and scanned documents to Markdown, tables and RAG chunks. OCR.
Convert PDF, Word, Excel, PowerPoint, e-mails and web pages to clean Markdown for LLMs.
Document to Markdown: convert Word, Excel, PowerPoint and PDF files to Markdown for an LLM.
Related MCP Servers
- AlicenseAqualityBmaintenanceA Model Context Protocol server that converts over 29 file formats, including PDFs, Office documents, and audio, into structured Markdown using Microsoft's MarkItDown library. It enables AI assistants to process diverse document types through single file conversion and batch directory processing.3109 PyPI46MIT
- AlicenseNot gradedqualityCmaintenanceConverts documents, webpages, and media files into markdown for AI assistants using Microsoft's MarkItDown and Crawl4AI. It enables tools to read PDFs, Office files, and JavaScript-rendered websites with support for OCR and image extraction.3MIT
- FlicenseNot gradedqualityDmaintenanceConverts documents (PDF, DOCX, images, etc.) to Markdown using Microsoft's Markitdown library, with no local setup required. Integrates with AI agents via MCP for seamless document conversion.1-

Docling MCPofficial
AlicenseAqualityAmaintenanceProvides tools for document conversion, processing, and generation, enabling PDF to structured JSON conversion, document creation, and caching for improved performance.216,079 PyPI784MIT