pdfluent-mcp
OfficialYou can read, inspect, search, and fill local PDFs through an MCP server that runs on your machine and keeps documents local.
Extract PDF content as markdown, plain text, tables, or positioned blocks (with page, bbox, confidence, and vision-needed pages).
Get metadata such as page count, title, author, dates, PDF version, encryption, forms, signatures, bookmarks, and pages without a text layer.
Search a PDF for text and get matching pages with snippets.
List interactive form fields and fill them into a new PDF without changing the original.
Ask which pages are worth sending to a vision model.
Restrict file access to allowed roots, with page, byte, and output-size limits.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pdfluent-mcp Convert report.pdf in ~/Documents to markdown and list its tables"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
An MCP server for PDFluent. It lets Claude Desktop, Claude Code, Cursor, VS Code and any other MCP client read a local PDF as markdown, plain text, tables or positioned blocks, look up its metadata, search it, and fill its form fields into a new file.
Runs on your machine, no upload. It runs over stdio, one process per client,
on the pdfluent Python package. Your documents stay on your machine. The
server reads and writes only inside the directories you allow. Your documents
are never uploaded.
Quick start
uvx pdfluent-mcp setup --root ~/DocumentsThis registers a stdio server named pdfluent in the user configs of Claude
Desktop, Claude Code, Cursor and Codex, then tells you to restart the clients.
pipx run pdfluent-mcp setup works the same way. Without --root, file access
relies on client MCP roots or PDFLUENT_MCP_ROOTS
(SETUP-001, SETUP-002).
Needs Python 3.10 or later and uv. uvx
downloads the server and pdfluent on first use and caches them. The balanced
quality tier needs model files; pdfluent models install downloads them once.
Related MCP server: file-analyzer-mcp
Tools
Tool | What it does | Example prompt |
| The document as markdown in reading order: headings, list items and tables. Running heads and page numbers are left out. | "Summarise ~/Documents/report.pdf." |
| The plain text layer, page by page, each page behind | "Give me the raw text of pages 0 to 2 of contract.pdf." |
| One entry per table with | "Pull the tables out of invoice.pdf." |
| Positioned blocks with | "List every heading in manual.pdf with its page." |
| Page count, title, author, dates, PDF version, encryption, form fields, signatures, bookmarks, and pages with no text layer. | "How many pages does scan.pdf have, and is it encrypted?" |
| The pages that mention a query, with up to three snippets per page. | "Which pages of policy.pdf mention retention?" |
| Every form field with | "Which fields does application.pdf have?" |
| Fills the named fields and writes a new file. The input is never changed. | "Fill application.pdf with my name and address, save as application-filled.pdf." |
| One entry per page with | "Which pages of scan.pdf need a vision model?" |
Page numbers are 0-based in every argument and result.
Tool | Returns |
| The document as markdown in reading order: headings, list items and tables. Running heads and page numbers are left out. |
| The plain text layer, page by page, each page behind |
|
|
|
|
| Page count, title, author, dates, PDF version, encryption, whether the document has form fields, how many signatures and bookmarks it has, and which pages have no text layer. |
| The pages that mention |
| Every form field with |
| Fills the named fields and writes a new file at |
|
|
confidence is the probability of the learned model that decided a block's
kind; it is null where no model decided it, and null means unknown, not
low.
Install per client
Replace /path/to/documents with the directory your PDFs live in.
Claude Desktop
Add to claude_desktop_config.json and restart Claude Desktop:
{
"mcpServers": {
"pdfluent": {
"command": "uvx",
"args": ["pdfluent-mcp", "--root", "/path/to/documents"]
}
}
}macOS: ~/Library/Application Support/Claude/claude_desktop_config.json,
Windows: %APPDATA%\Claude\claude_desktop_config.json.
If Claude Desktop does not find uvx, write its full path (which uvx) in
command.
Claude Code
claude mcp add pdfluent -- uvx pdfluent-mcp --root /path/to/documentsClaude Code also offers its working directory as an MCP root, so inside a
project claude mcp add pdfluent -- uvx pdfluent-mcp is enough. For a team,
put this in the project's .mcp.json:
{
"mcpServers": {
"pdfluent": {
"type": "stdio",
"command": "uvx",
"args": ["pdfluent-mcp"]
}
}
}To tell Claude when to reach for these tools, copy skills/pdfluent from this
repository to ~/.claude/skills/pdfluent (every project) or to
.claude/skills/pdfluent in one project.
Cursor
Add to Cursor (then change /path/to/documents), or add to
~/.cursor/mcp.json or the project's .cursor/mcp.json:
{
"mcpServers": {
"pdfluent": {
"type": "stdio",
"command": "uvx",
"args": ["pdfluent-mcp", "--root", "/path/to/documents"]
}
}
}VS Code
Install in VS Code, or from a terminal:
code --add-mcp '{"name":"pdfluent","type":"stdio","command":"uvx","args":["pdfluent-mcp","--root","/path/to/documents"]}'Or add to .vscode/mcp.json in the workspace (note the key is servers):
{
"servers": {
"pdfluent": {
"type": "stdio",
"command": "uvx",
"args": ["pdfluent-mcp", "--root", "/path/to/documents"]
}
}
}Codex
Add to ~/.codex/config.toml:
[mcp_servers.pdfluent]
command = "uvx"
args = ["pdfluent-mcp", "--root", "/path/to/documents"]One-click install for Cursor and VS Code registers the server with a placeholder root that you then change.
Reference
--root DIR(repeatable) is added to the saved command for each directory you name, for exampleuvx pdfluent-mcp setup --root ~/Documents.--dry-runshows what would change and writes nothing.Before it replaces a config file, setup saves the previous file next to it as
<name>.pdfluent-backup-<timestamp>and prints the path.--client claude-desktop|claude-code|cursor|codexlimits it to some clients (repeatable).uvx pdfluent-mcp uninstall(orsetup --uninstall) removes only thepdfluententry, and only when it was written bypdfluent-mcp(or with--force). It does not remove the Python package.
Close the clients before you run setup or uninstall. Files are replaced atomically, but no portable call lets setup detect a client that saves the same file in the last instant; a save in that gap can be lost, and where hard links are unavailable the backup is a plain copy and the gap is wider.
Setup keeps unrelated settings and servers, preserves TOML comments, and
refuses malformed configs and symbolic links. A different existing pdfluent
entry is left alone unless you pass --force
(SETUP-003). The saved launcher uses the absolute uvx
path when found, otherwise the current Python interpreter, which must stay
installed (SETUP-004).
Config files used: Claude Desktop's platform config (see above), Claude Code's
~/.claude.json, Cursor's ~/.cursor/mcp.json, and Codex's
~/.codex/config.toml (CODEX_HOME is respected).
pip install pdfluent-mcp
pdfluent-mcp --root ~/DocumentsThe server touches nothing outside its roots. Give them with --root (repeat
for more than one), with PDFLUENT_MCP_ROOTS (:-separated, ; on
Windows), or let the client offer them: Claude Code sends its working
directory and --add-dir directories as MCP roots. A server with no root from
any of these answers every call with a message saying so. Symlinks are
resolved before the check, so a link inside a root cannot point outside it.
A root is as wide as the directory it names. A client that offers /, ~
or a drive as an MCP root widens the server to everything the user can read;
if that is not what you want, start the server with --root on the folder
your PDFs live in and keep the client's roots narrow.
Three more limits: --max-pages (default 200) is how many pages one call
returns, so a long document is read in windows through pages (the engine
still parses the whole document for every window; the cap bounds the output,
not the work); --max-bytes (default 100 MiB) is the largest document the
server opens; --max-output-chars (default 200000) is the longest result one
call returns, after which it is cut and says so. All three also read from
PDFLUENT_MCP_MAX_PAGES, PDFLUENT_MCP_MAX_BYTES and
PDFLUENT_MCP_MAX_OUTPUT_CHARS.
The repository is also a Claude plugin (.claude-plugin/plugin.json). It
bundles the pdfluent skill from skills/ and starts the local MCP server with
uvx pdfluent-mcp==0.3.0 over stdio, so the plugin runs one pinned PyPI
package and nothing else. A local MCP server loads in Claude Code and in
Cowork sessions on your computer; chat on claude.ai ignores it.
What the plugin does with data: the server reads PDFs only inside the
directories you allow, and writes only the new file that fill_form creates
there. It stores nothing, keeps no data after a call returns, and sends nothing
to any other service. The one download is the pdfluent package and, if you
choose the balanced tier, the model files from pdfluent models install. The
plugin is not aimed at people under 18.
pip install -e ".[test]"
pytestThe tests start the server over stdio with a real MCP client, call every tool
on the PDFs in tests/fixtures, and try to step outside the allowed roots.
Licence
The same as the pdfluent package it runs on: AGPL-3.0-only, or the PDFluent
Commercial Licence. See LICENSE and LICENSE-COMMERCIAL. It depends on
mcp (MIT).
Privacy
Available Tools
9 toolsextract_blocksARead-onlyIdempotent
A local PDF as blocks, in reading order, with where each one came from.
Each block has kind (paragraph, heading, list_item, table_cell, header,
footer), text, page (0-based), bbox ([x0, y0, x1, y1] in PDF
points, origin bottom-left) and confidence: the probability of the
learned model that decided the block's kind, or null where no model did --
null means unknown, not low. Headings carry level, list items level
and ordinal, table cells row, column, row_span,
column_span and header.
pages_needing_vision lists the pages in the window whose text layer is
missing: nothing this returns for them is the page's content.
Args: path: The PDF's absolute path on this machine. pages: The 0-based pages to return; omit for the whole document, up to the server's page limit. include_furniture: Keep running heads and page numbers (kinds header and footer); they are left out by default because they repeat on every page and crowd out the content.
Inputs: path (required), pages, include_furniture. Returns: result
extract_markdownARead-onlyIdempotent
A local PDF as markdown, in reading order.
Headings become # to ###, list items - and 1., a table a pipe
table (or HTML where markdown cannot hold its shape), and a change of page an
HTML comment. Running heads and page numbers are left out.
Args:
path: The PDF's absolute path on this machine.
pages: The 0-based pages to return; omit for the whole document, up to
the server's page limit. The whole document is still read, because
what a block is gets decided against the rest of it.
quality: "fast" (default) or "balanced", the layout-model tier,
which needs the models installed on this machine.
Inputs: path (required), pages, quality. Returns: result
extract_tablesARead-onlyIdempotent
The tables of a local PDF as rows of cell text.
tables holds one entry per table in reading order: page (0-based),
rows (a list of rows, each a list of cell strings, every row the table's
width) and header_rows (how many leading rows are header rows). A
spanning cell sits at its first row and column; the cells it covers are
empty strings.
Args: path: The PDF's absolute path on this machine. pages: The 0-based pages to look at; omit for the whole document, up to the server's page limit.
Inputs: path (required), pages. Returns: result
extract_textARead-onlyIdempotent
The plain text layer of a local PDF, page by page.
Each page starts with <!-- page N --> (N 0-based). No reading-order
repair and no structure: use extract_markdown for that. A page with no text
layer (a scan) yields nothing here; get_metadata names those pages.
Args: path: The PDF's absolute path on this machine. pages: The 0-based pages to return; omit for the whole document, up to the server's page limit.
Inputs: path (required), pages. Returns: result
fill_formADestructiveIdempotent
Fill the form fields of a local PDF and write the result to a new file.
values maps a field name from list_form_fields to its new value: a
string for a text field, a check box or a combo box, a list of strings for
a multi-select list box. The input file is never changed; out_path must
be a different path inside an allowed root, and one that does not exist
yet unless overwrite is true. A symbolic link at out_path is
refused either way. The result names the fields that were set and the
names that were unknown; nothing is written when no field was set.
Args: path: The absolute path of the PDF to fill. values: Field name to new value. out_path: The absolute path to write the filled PDF to. overwrite: Replace a file that already exists at out_path.
Inputs: path (required), values (required), out_path (required), overwrite. Returns: result
get_metadataARead-onlyIdempotent
What a local PDF is, before reading it.
pages, title, author, subject, created, modified,
format (the PDF version), encrypted with the encryption filter
name, has_forms with the form_fields count, the number of
signatures and bookmarks, and pages_needing_vision: the 0-based
pages that draw ink but carry no text layer. A document that needs a
password to open answers encrypted: true and needs_password: true
and nothing else.
Args: path: The PDF's absolute path on this machine.
Inputs: path (required). Returns: result
list_form_fieldsARead-onlyIdempotent
The interactive form fields of a local PDF.
fields holds one entry per field: name (the fully qualified name
fill_form takes), type (text, button, choice, signature or unknown),
value (the current value, or null) and page (0-based, or null when
the field has no widget on a page). An empty list means the document has
no AcroForm fields.
Args: path: The PDF's absolute path on this machine.
Inputs: path (required). Returns: result
searchARead-onlyIdempotent
The pages of a local PDF that mention query, with a snippet each.
pages lists every matching 0-based page. snippets gives up to three
windows of text around the match on each of the first twenty matching
pages, so an agent can decide which pages to read in full with
extract_markdown. Matching is case-insensitive on the text layer; a scanned
page cannot match.
Args: path: The PDF's absolute path on this machine. query: The text to look for, as written in the document.
Inputs: path (required), query (required). Returns: result
vision_adviceARead-onlyIdempotent
Which pages of a local PDF are worth sending to a vision model, and why.
advice holds one entry per page. needs_vision is true when any reason holds. Today
only no_text_layer is measured -- the page draws ink but yields no text,
as a scan does; low_confidence_table and figure are always false
until the engine can measure them.
Args: path: The PDF's absolute path on this machine.
Inputs: path (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
Each tool targets a clearly distinct output or operation: markdown, plain text, tables, blocks, metadata, search, vision advice, and form listing/filling. Although several tools extract from the same PDF, their descriptions make the boundaries explicit and an agent can reliably choose between them.
All names use snake_case consistently, which is a clear convention. However, verbs are not fully uniform: extract_* dominates, but vision_advice is noun-oriented and search is a bare verb, so the set is mostly rather than perfectly consistent.
Nine tools is well-scoped for a PDF extraction and form-filling server. Each tool has a clear role and none appears redundant or merely decorative.
The surface covers the main PDF reading lifecycle: metadata, search, multiple extraction formats, vision triage, and form inspection/filling. Minor gaps remain, such as no direct page rendering or image extraction tool, but core workflows are supported.
Maintenance
Related MCP Connectors
Convert PDF documents to Markdown for AI agents through an authenticated remote MCP server.
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
Hosted MCP server: convert PDFs to clean, LLM-ready Markdown with tables, formulas and OCR.
PDF tools + QR over MCP: merge, split, rotate, text, metadata, malicious-content scan.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceMCP server that reads PDFs and exposes them as structured Markdown, metadata, outlines, images, and tables to LLM consumers via tools like pdf_read_markdown and pdf_info.Apache 2.0
- FlicenseNot gradedqualityCmaintenanceLocal MCP server that extracts text and structure from PDF, DOCX, PPTX, SVG, and PNG files, along with directory and metadata listing, for read-only document analysis by LLM hosts.-
- AlicenseNot gradedqualityCmaintenanceIt enables AI agents and MCP clients to read, fill, create, export, and reconstruct fillable PDF forms, plus extract, search, and edit text and layout blocks, entirely against local files over stdio.Apache 2.0
- AlicenseAqualityBmaintenanceLocal MCP server for PDFs: read PDFs into Markdown with tables, charts and OCR, export to Word, PowerPoint, EPUB and Excel, and merge, split, fill, compare and edit PDFs. Works only inside the folders you allow; nothing is uploaded.3088 npmApache 2.0