OpenDocKit
from opendockit import convert_file
result = convert_file("quarterly-report.hwp")
result.text # Markdown: headings, tables, lists, footnotes, LaTeX equations
result.sections # per page / slide / sheet — for chunking and citations ("page 3")
result.warnings # what was skipped or approximated, in plain sentencesWhy OpenDocKit
Most converters handle the happy path. OpenDocKit is built for the files people actually upload.
Structure, not just text. Merged table cells, multi-column PDFs, borderless tables, nested lists, footnotes, speaker notes, native charts as data tables, SmartArt as nested lists, Word / PowerPoint / Hancom equations as LaTeX, links and bold / italic as Markdown.
First-class Korean documents. A from-scratch HWP 5.x parser, HWPX, CP949 detection, NFC normalization, and the form-heavy tables Korean offices produce. Most general-purpose converters cannot read these at all.
Detects by content, not extension. An HTML table saved as
.xls, a CSV with a title block, an MHTML page named.doc— each is read as what it really is, and a warning tells you.Safe on untrusted uploads. Zip bombs, runaway merged-cell counts, recursive PDF objects and multi-gigabyte images are bounded.
IsolatedConverterruns every file in a disposable worker process with memory and time limits.Images in place. Pictures, charts and scanned pages are extracted, filtered, and — if you plug in a vision model — described right where they appeared in the document.
A hard character budget.
max_charsstops work instead of truncating afterwards, so a file that will be rejected anyway costs neither parsing time nor vision-model calls.Permissive by default. MIT licensed; everything a plain
pip install opendockitbrings in is MIT / BSD / Apache-style (no PyMuPDF, no pyhwp), with no ML models and no GPU. The only copyleft code is behind the opt-inheicextra.
Related MCP server: Knowledge Assistant MCP
Installation
pip install opendockit # conversion only — never touches the network
pip install "opendockit[openai]" # + image description with a vision model
pip install "opendockit[heic]" # + HEIC/HEIF images (pulls in GPL/LGPL-licensed codec libraries)
pip install "opendockit[langchain]" # + LangChain loader
pip install "opendockit[llamaindex]" # + LlamaIndex reader
pip install "opendockit[mcp]" # + MCP server for agentsRequires Python 3.12 or newer on Linux or macOS. Windows is not supported yet for HTML, email and EPUB (why).
Optional: install LibreOffice (brew install --cask libreoffice, apt install libreoffice)
to read legacy .doc and .ppt files. Every other format is read by OpenDocKit itself.
Quick start
Convert
from opendockit import convert, convert_file
result = convert_file("report.pdf") # from a path
result = convert(data, "report.pdf") # from bytes (the filename is only a hint)
print(result.text)
print(result.char_count, result.exceeded) # size of the output, and whether the limit stopped itconvert is synchronous, offline and deterministic (the one exception: .doc and .ppt start a local LibreOffice
process). Pictures are collected in result.images and the text keeps an
[Image] placeholder where each one was.
Describe images with a vision model
from opendockit import OpenAIImageDescriber, aconvert
result = await aconvert(data, "report.pdf", describer=OpenAIImageDescriber()) # reads OPENAI_API_KEYCharts become data tables, diagrams become lists, scanned pages are transcribed, and decorative images are dropped.
OpenAIImageDescriber(model) accepts any LangChain chat model, and anything with an
async describe(image) -> str method works as a describer. See docs/images.md.
Serve it
from opendockit import ConversionError, IsolatedConverter
async with IsolatedConverter(workers=2) as converter: # 2 GB and 2 minutes per file by default
try:
result = await converter.convert(data, filename)
except ConversionError as exc:
print(exc.code, exc) # stable code + a message safe to show usersOne bad file ends one worker; your server and the next upload carry on. In a script, run this under
if __name__ == "__main__": — the workers import the main module again. See docs/server.md.
Command line
opendockit report.pdf # Markdown on stdout, warnings on stderr
opendockit report.pdf --json # sections, metadata, warnings, images
opendockit report.pdf --count # just the character count
opendockit scan.pdf --describe # describe images with a vision model (uses OPENAI_API_KEY)LangChain, LlamaIndex and MCP
from opendockit.integrations.langchain import OpenDocKitLoader
from opendockit.integrations.llama_index import OpenDocKitReader
docs = OpenDocKitLoader("report.pdf", mode="sections").load() # one Document per page / slide / sheet
docs = OpenDocKitReader(mode="sections").load_data("report.pdf")opendockit-mcp --root ~/Documents # MCP server: Claude, Cursor and other agents read your documents as MarkdownWith mode="sections" each page, slide or sheet is its own Document, with its number in the metadata for citations. See docs/integrations.md.
Supported formats
Format | Sections | Highlights |
page | reading order across columns, ruled and borderless tables, form field values, headings from font size, repeated header/footer removal, scanned pages via vision model | |
DOCX | document | heading styles, list numbering, merged cells, charts → tables, SmartArt, footnotes/endnotes, equations → LaTeX, comments |
PPTX | slide | on-screen order, bullet levels, tables, charts → tables, SmartArt, equations, speaker notes |
XLSX · XLS · Excel 2003 XML · CSV | sheet | several tables per sheet, merged cells, number and date formats, charts, cell comments |
HWP · HWPX | document | outline headings, numbering, merged cells, captions, footnotes, equations → LaTeX |
ODT · ODS · ODP | document / sheet / slide | read directly from the package: headings, lists, merged cells, charts, formulas → LaTeX, speaker notes |
RTF | document | built-in parser: legacy code pages (CP949), tables with merged cells, lists, footnotes, pictures |
EPUB | document | chapters in reading order, pictures stored in the book, metadata |
DOC · PPT | document / slide | converted through LibreOffice when it is installed, then read like DOCX / PPTX |
HTML · MHTML | document | tables with rowspan/colspan, layout tables unwrapped, MathML → LaTeX, hidden elements removed |
Email ( | document | headers, HTML or plain body, forwarded messages, calendar invites |
TXT · Markdown | document | encoding detection (UTF-8, CP949, UTF-16, Windows-1252) |
Images | document / page | JPEG, PNG, WebP, GIF, BMP, TIFF, AVIF, and HEIC with the |
Legacy .doc and .ppt need LibreOffice installed; everything else is read by OpenDocKit itself. The full list of
what each format restores is in docs/formats.md; the honest list of what it cannot do is in
docs/limitations.md.
How it compares
We ran OpenDocKit, MarkItDown, Kreuzberg, Unstructured and Docling on the same files on a standard GitHub runner (method, raw results and how to rerun it):
Structure — OpenDocKit keeps the most: 49 of 49 checks such as "is the merged cell still attached to its row", against 36 for the next tool. The checks are ours, and 0.2.0 was written with them known; the report says what that means.
Formats — it reads 26 of the 31 formats tested without any model or service, the most of the five, and is the only one that reads HWP and HWPX.
Not the fastest, and no OCR — scans and images are read only through a vision model, where Docling and Unstructured read them offline. Kreuzberg is about thirty times faster, and legacy
.doc/.pptcost about a second each because they go through LibreOffice.
Examples
examples/ has one sample document per format and the Markdown OpenDocKit produces from each — with and
without a vision model — so you can judge the output before installing anything.
Documentation
What is extracted from each format and how it is rendered | |
| |
Extraction, filtering, vision models, custom describers | |
| |
LangChain, LlamaIndex and the MCP server | |
What an upload UI should tell its users | |
Why it is built this way, and how it was verified | |
Known gaps, stated plainly | |
Every deliberate trade-off, with the test that pins it |
Contributing
Contributions are welcome — bug reports with a minimal reproducing document are especially valuable. Start with CONTRIBUTING.md.
git clone https://github.com/hyeonsang010716/OpenDocKit.git && cd OpenDocKit
uv sync
uv run pytest -n auto -m "not timing" # the bulk of the suite, in parallel
uv run pytest -m timing # tests that measure time, one at a time
uv run ruff checkLicense
Available Tools
2 toolsconvert_documentARead-onlyIdempotent
Convert a local document to Markdown.
path: the file to read (absolute, or relative to where the server was started). sections: which pages, slides or sheets to return, by their numbers in document_outline: "3" or "2-5". Leave out for the whole document. max_chars: the most characters of the document to return (default 100,000). A longer text is cut there, and a note after it says so.
Inputs: path (required), sections, max_chars.
document_outlineARead-onlyIdempotent
Describe a local document without returning its text: format, title, size, and its pages, slides or sheets with their numbers, titles and lengths. Use it to decide which sections to ask convert_document for.
path: the file to read (absolute, or relative to where the server was started).
Inputs: path (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
The two tools have clearly separate purposes: `document_outline` returns metadata and structural information, while `convert_document` returns extracted text. Their descriptions explicitly explain how they work together, leaving no realistic chance of confusion.
Both names use snake_case and are descriptive, but the pattern is not fully uniform: `convert_document` is verb-first while `document_outline` is noun-first. This is a minor deviation and remains readable and predictable.
The server is very tightly scoped with only two tools. Both earn their place, but the surface is thin for a document-handling server and leaves little room for adjacent operations.
The core workflow is covered: inspect a document's structure, then convert selected sections to Markdown. Minor gaps exist, such as discovering supported formats or handling batch operations, but agents can reasonably work around them.
Maintenance
Related MCP Connectors
Documents to Markdown: PDF, DOCX, PPTX, XLSX, HTML. Scanned PDF pages read by AI.
Document to Markdown: convert Word, Excel, PowerPoint and PDF files to Markdown for an LLM.
Convert PDF, Word, Excel and scanned documents to Markdown, tables and RAG chunks. OCR.
Convert PDF, DOCX, XLSX and 25 other formats to clean Markdown for LLMs and RAG. No key or account.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceConverts PDFs, Office files, spreadsheets, emails, audio, and more to Markdown locally, enabling AI assistants to read and process them without cloud upload.MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with local documents (PDF, Markdown, TXT) through tools for discovery, reading, extraction, summarization, comparison, keyword extraction, search, and analysis, ensuring privacy and offline capability.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to inspect and convert PDF, PowerPoint, Excel, and many other file formats into clean, structured Markdown, with chunking support for long documents.Apache 2.0
- AlicenseAqualityCmaintenanceEnables AI agents and MCP-capable platforms to convert documents such as docx, pptx, xlsx, pdf, odt, rtf, epub, and csv into clean GitHub-Flavored Markdown through a single tool call. Runs fully locally with no API key, no network access, and no OCR, returning structured errors for scanned, encrypted, or unsupported files.113 npmMIT