Docling
Shipped in 0.14.0 (TAN-3648, framework PR #153, commit eeb16b48). DoclingTools is the 63rd POJO toolkit and contributes one @Tool method.
DoclingTools converts a local document through Docling. TnsAI does not bundle Docling, Python, or models. You install one of:
- the official Docling MCP server, sharing the same filesystem as the JVM so the admitted source path is resolvable
- a local
doclingCLI onPATH(or an explicit executable path)
PdfTools stays PDFBox-first. Docling page rendering is an explicit constructor argument and runs only when PDFBox cannot open the admitted file. The default PdfTools constructors use DoclingProvider.noOp().
See the framework Changelog — the 0.14.0 entry (2026-08-18) covers it.
Register
import com.tnsai.agents.AgentBuilder;
import com.tnsai.enums.BuiltInTool;
agentBuilder.builtInTools(BuiltInTool.DOCLING_TOOLS);The LLM-visible method is docling_parse. It returns Markdown only, truncated at 100_000 characters. Structured tables, formulas, figures, and lossless Docling JSON require the Java parse(Path) API.
The no-arg DoclingTools constructor probes a docling executable lazily. DoclingTools.builder() starts from DoclingProvider.noOp() until you call docling(...).
MCP vs CLI
MCP (DoclingProvider.mcp) | CLI (DoclingProvider.subprocess) | |
|---|---|---|
| Runtime | Official Docling MCP server; TnsAI is an MCP client | Local docling process via ProcessBuilder — never a shell |
| Trust | String factory accepts loopback HTTP(S) only (localhost / 127.0.0.1 / ::1), no user-info in the URL. Remote servers need a caller-supplied McpClient whose server can resolve the same admitted path | Executable name or path only (no \0, max 4_096 chars). The source path is an argv element |
| Deploy | MCP server + shared filesystem (or a custom client that can see the file) | docling installed; Python/models live in that install |
| Availability | available() is true for a validated loopback URL | Cached docling --version probe, 5 s timeout. Missing binary → available() == false |
| On miss | Conversion throws | parse delegates to noOp(), which throws IOException("Docling is unavailable; configure an MCP endpoint or install the docling CLI") |
| Timeout | 5 minutes per MCP tool call; 200 ms minimum interval between calls | 5 minutes per conversion; temp output capped at 64 MiB |
| Output caps | Exported Markdown capped at 1_000_000 characters | Each .md / .json / page PNG read capped at 10 MiB |
| MCP tools | convert_document_into_docling_document, then export_docling_document_to_markdown | docling convert --to md --to json |
Both providers go through FileGuard and DoclingTools.DEFAULT_EXTENSIONS (pdf, Office, HTML, Markdown, images, wav/mp3/vtt, xml, latex/tex).
Configure MCP
import com.tnsai.tools.document.docling.DoclingProvider;
import com.tnsai.tools.document.docling.DoclingTools;
import com.tnsai.tools.document.docling.DocumentResult;
DoclingTools tools = DoclingTools.builder()
.docling(DoclingProvider.mcp("http://127.0.0.1:9000/mcp"))
.build();
DocumentResult result = tools.parse(Path.of("/data/paper.pdf"));
String markdown = result.markdown();
boolean structured = result.hasStructuredContent();A pre-connected client is DoclingProvider.mcp(mcpClient) when the server is not loopback but can still read the admitted path.
Configure CLI
DoclingTools tools = DoclingTools.builder()
.docling(DoclingProvider.subprocess("docling"))
.build();
DocumentResult result = tools.parse(Path.of("/data/paper.pdf"));Or new DoclingTools() — same lazy docling probe, FileGuardConfig.defaults().
PdfTools fallback
import com.tnsai.tools.document.docling.DoclingProvider;
import com.tnsai.tools.file.FileGuardConfig;
import com.tnsai.tools.file.PdfTools;
PdfTools pdf = new PdfTools(
FileGuardConfig.defaults(),
DoclingProvider.subprocess("docling"));PDFBox still renders first. Docling renderPages runs only after PDFBox fails to open the file. No configured provider (noOp()) means that failure stays a PDFBox error.
Not this page
- FILE RAG ingest extractors (
PdfContentExtractor, office SPI) — document formats - Heading-aware analysis split — SmartDocumentSegmenter, not Docling
- Installing Docling itself — upstream Docling docs