# docling-rs
The command-line interface of [docling.rs](https://github.com/docling-project/docling.rs)
— a Rust port of IBM's [docling](https://github.com/docling-project/docling).
One static binary converts PDF, Office, HTML, scans, audio and 40-odd other
formats to Markdown, docling JSON, HTML, text, DocLang, LaTeX, Pandoc AST,
WebVTT or RAG chunks; `docling-rs serve` is the HTTP API and
`docling-rs mcp` a Model Context Protocol server for AI agents.
```bash
```
## Usage
```bash
docling-rs report.pdf > report.md # Markdown, streamed page by page (--no-stream to buffer)
docling-rs --strict report.docx # the cleaner Markdown dialect
docling-rs report.pdf --to json # docling JSON; also html, text, dclx, latex, pandoc, vtt, chunks, images
docling-rs --images referenced report.pdf > out.md # pictures to ./artifacts/*.png (embedded = data: URIs)
docling-rs recording.mp3 # Whisper transcript; --asr-model whisper_tiny_en for a preset
docling-rs "data:text/html;base64,PGgxPkhpPC9oMT4="
docling-rs --help # every flag; --version lists the compiled-in features
docling-rs --list-input-formats # what this build converts, one per line
```
Every option — OCR engine and language, page ranges, image handling,
enrichment, PII redaction, the VLM pipeline — is in
[`docs/OPTIONS.md`](../../docs/OPTIONS.md); the library guide
([`crates/docling`](../docling/README.md)) explains what each does.
## Batch conversion — several sources, `--input` / `--output`
One warm process converts many documents (#205, #489): any number of
positional sources — files, directories, quoted globs, ZIP archives — or
`--input GLOB|DIR`, into `--output DIR`. The ML models load once; a failing
file is reported and skipped (non-zero exit at the end, `--abort-on-error`
to stop at the first); output paths print to stdout, progress to stderr.
```bash
docling-rs a.docx sub/b.docx other/c.pdf --output ./converted # a.md, b.md, c.md
docling-rs --to md,json report.pdf --output ./converted # report.md + report.json
docling-rs --input '/data/reports/**/*.pdf' --output ./out --to json # tree kept: out/2024/q1/a.json
docling-rs --input /data/reports --output ./out # recursive sweep, convertible files only
docling-rs bundle.zip --output out/ # every document inside: out/bundle/<entry>.md (#557)
```
| `--to FMT[,FMT]` (repeatable) | every format for each document; several need `--output` |
| `--output DIR` · `--output-file PATH` | the output directory · one input, one format, exactly that path (#611) |
| `--output-dirs auto\|flat\|mirror` | layout under `--output` (#496): mirror a directory's / glob's tree, land plain files by stem (default); everything flat as `<stem>.<ext>`; everything by its path relative to the CWD |
| `--images referenced` | each document's pictures in a sibling `<stem>_artifacts/` |
| `--jobs N` | declarative formats in parallel (PDFs share the one warm pipeline) |
| `--abort-on-error` | stop at the first failed file (Python's flag) |
| `--list-input-formats` · `--list-output-formats` | what this build converts, one per line (#603) — ask the binary instead of hard-coding a list |
| `-` · `http(s)://…` · `data:…` · `file:…` | stdin, a fetched URL, an inline document, a path through the URL grammar — as sources anywhere a path goes (#668); `--from FORMAT` / `--mime-type TYPE` type what carries no extension, `--no-url-fetch` refuses URLs |
Every other flag (`--strict`, `--pages`, `--ocr-lang`, `--pipeline vlm`,
enrichment, …) applies to the whole batch. Collision rules, the ZIP limits
and outcomes, email attachments (`EmailAttachments`, Python
`email_attachments()`, Node `emailAttachments()`, #561) and the progress /
exit-code details: [`docs/OPTIONS.md` § CLI batch
mode](../../docs/OPTIONS.md#cli-batch-mode).
## MCP server — `docling-rs mcp`
`docling-rs mcp` (#669) is a [Model Context Protocol](https://modelcontextprotocol.io)
server, so agents — Claude Desktop, Claude Code, Cursor, VS Code, any MCP
client — convert documents themselves. It is in the default build: the
release binaries, `cargo install docling-cli` and the `ghcr.io/docling-project/docling-rs`
image all carry it, no Python needed. Three tools:
| `convert_to_markdown(uri)` | Markdown of the document behind an `http:`/`https:`/`file:`/`data:` URI or a path — **MarkItDown's MCP tool, same name and contract**, so a `markitdown-mcp` setup switches by changing the command |
| `convert(uri, to?, images?, options?)` | `to` = `md` (default), `json` (docling's `DoclingDocument`), `html`, `text`, `latex`, `chunks`, `vtt`, `pandoc`; `options` = the [shared conversion options](../../docs/OPTIONS.md) (`{"pages": "1-5"}`, `{"text_layer_only": true}`, `{"ocr_lang": "ch"}`, `{"password": "…"}`, …) |
| `list_input_formats()` | the extensions this server converts |
Claude Desktop (`claude_desktop_config.json`) or any client that launches
stdio servers:
```json
{
"mcpServers": {
"docling": {
"command": "docling-rs",
"args": ["mcp", "--root", "/Users/me/Documents"]
}
}
}
```
```bash
claude mcp add docling -- docling-rs mcp --root ~/Documents # Claude Code
```
The container image has the models baked in; mount the folder at the same
path inside so the paths the agent sees are the paths the server reads:
```json
{
"mcpServers": {
"docling": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "/Users/me/Documents:/Users/me/Documents",
"ghcr.io/docling-project/docling-rs", "mcp", "--root", "/Users/me/Documents"]
}
}
}
```
Streamable HTTP instead of stdio, for clients that connect to a URL:
`docling-rs mcp --http` serves `http://127.0.0.1:3001/mcp` (`--host`,
`--port`; `--bearer-token` or `DOCLING_RS_MCP_TOKEN` to require
`Authorization: Bearer …`).
What a tool call may reach is the operator's decision, not the model's:
local paths and `file:` URIs are confined to `--root` (repeatable; the
working directory by default, checked before and after resolving symlinks);
`http(s)` URLs — and remote images, a request-supplied `vlm_endpoint` — only
with `--allow-url-fetch`, through the SSRF block-list on every redirect hop
with a 256 MiB / 300 s cap; `--http` refuses a non-loopback bind without
`--allow-remote` and checks `Host`/`Origin` on loopback. Details in
[docs/SECURITY.md](../../docs/SECURITY.md#docling-rs-mcp-model-context-protocol-server-669).
Markdown comes with compact tables (fewer tokens; `"compact_tables": false`
for docling's padded ones). Without the layout models (a bare release
binary — fetch them with `scripts/install/download_dependencies.sh`, or point
`DOCLING_RS_MODELS_DIR` at a `.models` directory in the client's `env`), PDFs
convert from their text layer, as MarkItDown's do, instead of failing.
The PDF/image models load on the first call that needs them and stay loaded
— one warm pipeline per server, as in `docling-serve` — so later calls skip
the load (a 5-page PDF: 5.4 s first, 2.6 s after), and memory stays flat
between calls (~0.6 GB with the models resident; ONNX Runtime's CPU arena is
off and freed buffers go back to the OS — `DOCLING_RS_NO_ARENA=0` restores
the arena). Calls carrying a progress token get a heartbeat every 10 s while
a long PDF converts.
## HTTP server
`docling-rs serve` (built with `--features serve`) runs the HTTP conversion
API, the same as the standalone `docling-serve` binary:
[`crates/docling-serve`](../docling-serve/README.md).
## License
MIT, like the rest of docling.rs.