Back to blog

Docling MCP Server: Setup, Tools and Tested Client Configs

How to run docling-mcp 3.5.0 over stdio and HTTP with Claude Code, Codex and the MCP Python SDK. The 21 tools, timings on five real PDFs, and every failure we hit.

The Docling MCP server is the docling-mcp package, which gives an MCP client tools to convert documents with Docling and read the result as Markdown. It worked in our tests over stdio and HTTP, from Claude Code, Codex and a script using the official MCP Python SDK. Two defaults will trip up a first setup. The conversion mode defaults to remote, so a plain install has nothing to convert with until you point it at Docling Serve or install the local extra. The transport defaults to streamable-http, so a client config without --transport stdio never connects.

We installed docling-mcp 3.5.0, released on November 4, 2026, and ran its tools on five PDFs. We also ran 3.2.0, the version locked by docling-serve 1.32.0. Everything below was run on our machine unless it is labeled untested. Disclosure: Parsebridge, which publishes this blog, sells a hosted Docling API.

Docling MCP at a glance

Result
Packagedocling-mcp 3.5.0, MIT license, Python 3.10 or newer
Commanddocling-mcp-server
Transportsstdio, sse, streamable-http (the default). All three ran.
Default addresslocalhost:8000, endpoint /mcp
Conversion modesremote (the default, needs Docling Serve) or local (needs the local extra)
Default tools21, plus 7 prompts
Install size151 MB for remote only, 1.1 GB with local, plus 506 MB of Hugging Face models on first use
Local server memory2,969 to 4,023 MB peak across three runs that included a 60-page PDF
60-page report, local249 to 337 seconds to convert on an Apple M4 CPU, with 715,071 characters of Markdown
Clients we ranClaude Code 2.1.318, Codex CLI 0.166.0, MCP Python SDK 2.3.0
Clients not testedClaude Desktop, Cursor, LM Studio

Hosted Docling API

Parsebridge, which runs this blog, does not have an MCP server. It is a hosted Docling API. You send a PDF as a file upload or a URL and get Markdown back in a JSON response, with no models or Docling process on your machine. Agents that can call an HTTP endpoint can use it directly, and you would write that tool yourself. It also cannot serve as DOCLING_MCP_SERVICE_URL, because it has its own request shape and does not expose the Docling Serve routes. Signing up gives you 50 free pages, and plans start at $17 a month for 5,000 pages. Where each option fits has the detail.

How we tested

The machine was a Mac mini with an Apple M4 and 16 GB RAM, on macOS 26.6 and Python 3.12.15, using the CPU and no GPU.

Setupdocling-mcpMCP SDKDoclingdocling-core
Local mode3.5.02.3.02.147.02.106.0
Remote client3.5.02.3.0conversion runs on the server2.106.0
docling-serve 1.32.0, from its uv.lock3.2.02.1.12.124.02.93.0

The two docling-serve 1.32.0 containers we run in production also report docling-mcp 3.2.0 and MCP SDK 2.1.1, and set no DOCLING_MCP_ variables. We did not run the server inside a container, because the test machine has no Docker. We ran the same docling-mcp-server command from the environment installed from that lockfile.

We used the same PDFs as our Docling chunking guide:

Install docling-mcp

For local conversion, install the local extra. We used uv:

uv venv --python 3.12 venv-local
uv pip install --python venv-local/bin/python 'docling-mcp[local]==3.5.0'

That environment was 1.1 GB after install and 1.3 GB after use, with the OCR models stored inside it. For remote mode only, leave out the extra, and the environment was 151 MB:

uv venv --python 3.12 venv-remote
uv pip install --python venv-remote/bin/python 'docling-mcp==3.5.0'

You can also let the client start it through uvx, which is how the project’s README does it:

DOCLING_MCP_CONVERSION_MODE=local uvx --from 'docling-mcp[local]==3.5.0' docling-mcp-server --transport stdio

With an empty uv cache and a busy machine (load average around 20), uvx took 55 seconds to answer the MCP initialize request and left 2.4 GB in the cache. The next start took 2.9 seconds. A client with a short startup timeout could give up on that first start, so it helps to run the command once in a terminal first.

Local mode downloads its models on the first conversion. With an empty Hugging Face cache, also on a busy machine, the first conversion of the one-page table took 64 seconds and put 506 MB in the cache. The server log showed Auto OCR model selected rapidocr with torch.

Connect a client

Claude Code (tested)

We saved this file as docling-mcp.json, using the absolute path to the installed server:

{
  "mcpServers": {
    "docling": {
      "command": "/absolute/path/to/venv-local/bin/docling-mcp-server",
      "args": ["--transport", "stdio"],
      "env": {
        "DOCLING_MCP_CONVERSION_MODE": "local",
        "CACHE_DIR": "/absolute/path/to/docling-cache"
      }
    }
  }
}

We then ran it non-interactively:

claude -p --mcp-config docling-mcp.json --strict-mcp-config \
  --allowedTools "mcp__docling__*" \
  "Use the docling MCP tools to convert /absolute/path/to/table.pdf and export it to Markdown. Then tell me the first line of the document and the name of the first row label under the table header. Answer in two short lines."

Claude Code reported the server as connected with 21 tools, called the conversion tool and then the export tool, and answered:

First line: `## Table 1. U.S. Energy Markets Summary`
First row label under the header: `Energy Production`

The same client also connected to a running HTTP server with this entry:

{ "mcpServers": { "docling": { "type": "http", "url": "http://localhost:8765/mcp" } } }

Codex CLI (tested, with one failed attempt)

We passed the server config as -c overrides and did not edit config.toml:

codex exec --skip-git-repo-check -s read-only \
  -c 'mcp_servers.docling.command="/absolute/path/to/venv-local/bin/docling-mcp-server"' \
  -c 'mcp_servers.docling.args=["--transport","stdio"]' \
  -c 'mcp_servers.docling.env={DOCLING_MCP_CONVERSION_MODE="local",CACHE_DIR="/absolute/path/to/docling-cache"}' \
  -c 'mcp_servers.docling.default_tools_approval_mode="approve"' \
  "Use the docling MCP tools to convert /absolute/path/to/form.pdf and export it to Markdown. Tell me the first heading in the document. One line." < /dev/null

Three details came out of the runs:

  • Our Codex config sets approval_policy = "never". Without the default_tools_approval_mode line, the call failed with MCP tool call requires approval, but approval policy is never.
  • With that line set, two of three small-PDF runs worked, and they answered The first heading is "Form W-4". The third reported that the Docling tools were not available in the session. We did not find the cause. The Codex docs list a default startup_timeout_sec of 10, and our warm server starts took 2.9 to 4.5 seconds.
  • The same docs list a default tool_timeout_sec of 60. With that setting unset, a report conversion ran to completion anyway, in a 294-second Codex run. A second run with tool_timeout_sec=900 also completed. We would set the value explicitly and would not rely on either behavior.

Without the < /dev/null, codex exec printed Reading additional input from stdin... and did not proceed.

MCP Python SDK (tested)

This script uses the official mcp package, version 2.3.0, with docling-mcp-server on the PATH:

import asyncio
import sys

from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client

server = StdioServerParameters(
    command="docling-mcp-server",
    args=["--transport", "stdio"],
    env={"DOCLING_MCP_CONVERSION_MODE": "local"},
)


async def main(pdf: str) -> None:
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print(len(tools.tools), "tools")

            converted = await session.call_tool(
                "convert_document_into_docling_document", {"source": pdf}
            )
            print(converted.structured_content)

            exported = await session.call_tool(
                "export_docling_document_to_markdown",
                {"document_key": converted.structured_content["document_key"]},
            )
            print(exported.structured_content["markdown"][:300])


asyncio.run(main(sys.argv[1]))

On the scanned order, it printed:

21 tools
{'from_cache': False, 'document_key': 'ef846439fd43fc30c126c3497975b035'}
## SAMPLE ORDER

Synthetic OCR test fixture - no real customer data

Order number: PB-1042

Order date: 2026-09-11

## Ship to

Example Research Lab 42 Sample Street Zurich, Switzerland

| Item            |   Quantity | Amount    |
|-----------------|------------|-----------|
| Archive folders |

Claude Desktop and Cursor (untested)

We did not run either of these. The MCP docs place the Claude Desktop file at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, and the Cursor docs use .cursor/mcp.json in a project or ~/.cursor/mcp.json globally. Both document the mcpServers shape with command, args and env, so this entry follows their formats:

{
  "mcpServers": {
    "docling": {
      "command": "/absolute/path/to/venv-local/bin/docling-mcp-server",
      "args": ["--transport", "stdio"],
      "env": { "DOCLING_MCP_CONVERSION_MODE": "local" }
    }
  }
}

The config in the docling-mcp README passes only --from=docling-mcp docling-mcp-server to uvx, with no --transport stdio and no conversion mode. In our tests, running that server command with no transport flag started an HTTP server on localhost:8000, and our stdio client was still waiting on initialize when we stopped at 30 seconds. Claude Code listed the server as pending with 0 tools. We ran that test with the installed binary, without uvx.

The tools docling-mcp exposes

docling-mcp 3.5.0 loads 21 tools from three groups by default:

GroupTools
conversion (5)convert_document_into_docling_document, convert_directory_files_into_docling_document, check_document_in_local_cache, list_cached_documents, remove_document_from_local_cache
generation (11)export_docling_document_to_markdown, save_docling_document, get_page_thumbnail, create_new_docling_document, add_title_to_docling_document, add_section_heading_to_docling_document, add_paragraph_to_docling_document, open_list_in_docling_document, close_list_in_docling_document, add_list_items_to_list_in_docling_document, add_table_in_html_format_to_docling_document
manipulation (5)get_overview_of_document_anchors, search_for_text_in_document_anchors, get_text_of_document_item_at_anchor, update_text_of_document_item_at_anchor, delete_document_items_at_anchors

It also registers 7 prompts, such as convert_and_summarize and find_and_replace_in_document.

You can load fewer tools by listing groups after the options. The Markdown export lives in generation, so conversion alone gave 5 tools and no way to read a document as Markdown:

docling-mcp-server --transport stdio conversion generation   # 16 tools

The CLI also accepts llama-index-rag, llama-stack-rag and llama-stack-ie groups. We did not test them.

Version 3.2.0, the one in docling-serve 1.32.0, has 19 tools and uses older names for two of them: is_document_in_local_cache and page_thumbnail. It has neither list_cached_documents nor remove_document_from_local_cache. A prompt or script written against one version can break on the other.

How the tools behave on real PDFs

Conversion returns a key and no text:

{ "from_cache": false, "document_key": "7251e74440cf663770423f4f01301301" }

You pass the key to the other tools. The export of the EIA table kept its structure, with quarters in the header:

## Table 1. U.S. Energy Markets Summary

U.S. Energy Information Administration | Short-Term Energy Outlook - October 2026

| | 2025 - Q1 | 2025 - Q2 | 2025 - Q3 | ...
|-|-----------|-----------|-----------| ...
| Energy Production | | | | ...
| Crude Oil Production (a) (million barrels per day) ........ | 13.32 | 13.58 | 13.82 | ...
| Dry Natural Gas Production (billion cubic feet per day) ... | 105.5 | 106.9 | 108.3 | ...

We collapsed the column padding and dot leaders above to fit the page and cut the rows at .... On the W-4, the anchor overview gave an agent a map of the document before it read any text:

[anchor:#/texts/0] section_header-1: Form W-4
  [anchor:#/texts/1] text
[anchor:#/texts/2] section_header-1: Employee's Withholding Certificate
  [anchor:#/texts/3] text

We trimmed that output and its indentation. Other behavior we confirmed:

  • Cache keys: the key stayed the same across server restarts, and an absolute and a relative path to the same file gave the same key, so repeat conversions in one process came back in 0.08 to 0.53 seconds with from_cache: true.
  • Cache lifetime: the cache lives in the server’s memory. After a restart, list_cached_documents was empty and exporting the old key failed, so you have to convert again. The README sets the default capacity to 10 documents through DOCLING_MCP_CACHE_MAX_DOCUMENTS. We did not test eviction.
  • Shared cache over HTTP: a second HTTP session saw the document the first session converted. Over stdio, each client process starts its own server, with its own cache.
  • Directories: convert_directory_files_into_docling_document converted the files directly in the folder and skipped a PDF in a subfolder.
  • URLs and other formats: a public PDF URL converted in 7.7 seconds. A short Markdown file, HTML file and text file also returned keys, and we did not inspect their output.
  • Saving files: save_docling_document writes one .md and one .json file. Without CACHE_DIR, ours landed in site-packages/_cache inside the virtual environment, so set CACHE_DIR if you want to keep them.
  • Thumbnails: get_page_thumbnail needs DOCLING_MCP_KEEP_IMAGES=true. With it set, a 256-pixel request returned a PNG image. Without it, the call failed.
  • Truncation: max_size=200 cut the W-4 Markdown mid-word, at from your p.

Large documents

The full export of the 60-page report was 715,071 characters. Claude Code did not pass it to the model and returned this instead:

Error: result (717,517 characters) exceeds maximum allowed tokens. Output has been saved to [a file under ~/.claude/projects/]

Claude Code then read page 5 inline through page_no. Exporting each page with page_no gave a median of about 3,300 characters per page, a minimum of 14 and a maximum of 85,649 on page 55. Most of the size in this report is table padding and dot leaders. Removing runs of dots and repeated spaces took the full export from 715,071 to 244,308 characters. For long documents, have the agent read the 23,348-character anchor overview, or search with search_for_text_in_document_anchors, and then export only the pages it needs.

Timings

These are wall times for convert_document_into_docling_document as measured by the MCP client, with a single server process per run and the PDFs converted in the order shown. The first row of each run includes loading the models. Local mode ran three times over stdio, and the “Local” column is the run with the lowest machine load (load average 2 to 5). Other work on the machine overlapped the other runs, which is why the range is wide.

PDFPagesLocal, secondsLocal, range over 3 runsRemote via docling-serve 1.32.0, secondsMarkdown, characters
Table19.39.3 to 32.213.610,555
Form15.55.5 to 26.95.54,720
Scan16.15.4 to 22.72.8494
Paper1012.811.6 to 41.313.950,469
Report60248.8248.8 to 336.8437.5715,071

The remote column is one run on a load average of 5 to 8, with a different Docling version on the server (2.124), so do not read the two columns as a speed comparison. Markdown export took between 0.002 and 0.6 seconds in every run. Server start to initialize took 2.9 to 4.5 seconds in local mode with models cached. The server’s peak memory was 4,023, 3,294 and 2,969 MB across the three local runs.

Run it over HTTP

Streamable HTTP is the default transport, so this is all it takes:

DOCLING_MCP_CONVERSION_MODE=local docling-mcp-server --transport streamable-http --port 8765

From the Python SDK, connecting with streamable_http_client("http://localhost:8765/mcp") listed 21 tools and converted the table PDF in 10.1 seconds. The sse transport at http://localhost:8765/sse also listed 21 tools and converted the same PDF.

A long conversion did not block other sessions. While one session converted the 60-page report, a second session initialized in 0.01 seconds, listed the cache in 0.06 seconds and converted the W-4 in 11.1 seconds. The report took 700 seconds in that run, with a load average of 20 to 30 from other work on the machine, so we can’t say how much of that came from the overlap.

The server has no authentication option on its command line, and we connected without credentials in every HTTP test. On the default localhost binding, a request with Host: evil.example.com got 421 Invalid Host header. With --host 0.0.0.0, the port listened on all interfaces, and an initialize request to the machine’s LAN address returned 200 with no credentials. The conversion tools accept local file paths, so anyone who can reach an exposed port can read documents the server’s user can open. Put your own authentication in front if it has to leave the machine.

Remote mode with Docling Serve

In remote mode, the MCP server stays small and sends conversions to Docling Serve. We started docling-serve 1.32.0 on port 5001 and used the 151 MB install:

export DOCLING_MCP_SERVICE_URL=http://127.0.0.1:5001
docling-mcp-server --transport stdio

Local file paths work, because the MCP server uploads the file. The server’s log showed each upload as POST /v1/convert/file/async returning 422 and then 200, and the conversions completed, so that first 422 is safe to ignore. With DOCLING_SERVE_API_KEY set on the server, conversion failed without DOCLING_MCP_SERVICE_API_KEY (a 401 in the logs) and worked with it.

The important setting here is DOCLING_MCP_SERVICE_TIMEOUT, which defaults to 300 seconds. Our first remote run on the 60-page report failed at 301.4 seconds. The client saw only the generic error, and the server log said:

TaskTimeoutError: Timed out waiting for task e47120a2-0b2f-4588-80b5-e9b3998b119f after 300.00s.

With DOCLING_MCP_SERVICE_TIMEOUT=1200, the same PDF finished in 437.5 seconds. Our Docling Serve guide covers setting up the server.

The MCP server inside docling-serve

The docling-serve 1.32.0 docs start the MCP server from the serve image with this command, which we did not run because we had no Docker:

podman run -p 8000:8000 quay.io/docling-project/docling-serve -- docling-mcp-server --transport streamable-http --port 8000 --host 0.0.0.0

That page sets neither a conversion mode nor a service URL. We ran the same docling-mcp-server arguments from an environment installed from the docling-serve 1.32.0 lockfile. The client connected and listed 19 tools, and conversion failed because version 3.2.0 also defaults to remote. Setting DOCLING_MCP_CONVERSION_MODE=local fixed it in that environment, and the table PDF converted in 15.5 seconds. Pointing it at a running Docling Serve with DOCLING_MCP_SERVICE_URL worked too, in 13.7 seconds.

The version difference also changed the Markdown. In remote mode the MCP server renders Markdown itself from the JSON that Docling Serve returns, so the output depends on the docling-core in the MCP environment. From the same server, 3.5.0 (docling-core 2.106) wrote one header row with 2025 - Q1, while 3.2.0 (docling-core 2.93) wrote 2025 in the header and put Q1 in the first body row.

What failed

Most failures reached the client as one generic line, Error executing tool convert_document_into_docling_document. The reason is only in the server’s stderr, so check there first. In Claude Desktop, the MCP docs say server logs are under ~/Library/Logs/Claude on macOS.

What we didWhat the client sawWhat the server log said
Default install, no service URLGeneric errorDOCLING_MCP_SERVICE_URL is not set but DOCLING_MCP_CONVERSION_MODE=remote, followed by the two ways to fix it
DOCLING_MCP_CONVERSION_MODE=local without the local extraGeneric errorModuleNotFoundError: No module named 'packaging', which does not mention the missing extra
Service URL with nothing listeningGeneric errorServiceUnavailableError: Service transport request failed.
Remote conversion over 300 secondsGeneric errorTaskTimeoutError, as shown above
Missing fileGeneric errorConversionError: Conversion failed for: does-not-exist.pdf
Export with an unknown keyGeneric errorValueError: document-key: nope is not found.
Thumbnail without DOCLING_MCP_KEEP_IMAGESGeneric errorValueError: The DoclingDocument does not have page images.
Export with page_no=99 on a one-page PDFpage_no=99: not found in the document. Available pages are: 1This one reached the client
Client config with no --transport stdioinitialize never returnedUvicorn running on http://localhost:8000

Where a hosted API fits

Run docling-mcp when you want an agent to work inside a document with anchors, search, edits and page thumbnails. These need a DoclingDocument, and a Markdown-only API can’t provide them. Local mode also converts on your machine, although a cloud-based client still sends whatever the agent reads to its model provider. The costs we measured were 1.1 GB of packages, 506 MB of models, up to 4 GB of memory, and 4 to 6 minutes of conversion time on our CPU for the 60-page report. Remote mode moves that work to a Docling Serve instance you operate.

Parsebridge fits when you only need PDF to Markdown in an application and would prefer not to run any of that. It runs Docling 2.124 inside docling-serve 1.32.0, accepts PDFs up to 50 MB as an upload or URL, and returns Markdown. There is no MCP server, so an agent would call it through a tool you write. There are no DoclingDocument results, anchors, or edit tools, and your PDF is sent to our service. New accounts get 50 free pages once, and plans start at $17 a month for 5,000 pages.

To see Docling’s output on one of your own PDFs first, the free PDF to Markdown converter converts the first page of a PDF up to 10 MB without an account, five times per hour. For Python without MCP, see Getting started with Docling in Python.


Every command and result above was run on November 4, 2026, using docling-mcp 3.5.0 and the 3.2.0 locked by docling-serve v1.32.0, except where a section says untested. Defaults, tool names and environment variables were read from the docling-mcp v3.5.0 source.