pdf-mcp
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., "@pdf-mcpextract text from sample.pdf"
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.
pdf-mcp
Full-stack PDF intelligence MCP server — extract, manipulate, annotate, convert, validate, and RAG-search PDFs through a unified tool surface and React workbench.
v0.2.1 · Ports 11130 (frontend) / 11131 (backend)
FastMCP 3.4.4 · PyMuPDF + pypdf + pdfplumber · LanceDB RAG · Prefab UI · dual transport (stdio + HTTP)
Features
pdf_extract — text, images, tables, metadata, fonts, links, outline
pdf_manipulate — merge, split, rotate, reorder, delete pages, compress, encrypt/decrypt, optimize
pdf_annotate — watermark, stamp, highlight, underline, header/footer, page numbers, auto summary box
pdf_forms — list / fill / flatten / export + LLM-guided auto-fill
pdf_convert — PDF ↔ Markdown / images / HTML
pdf_validate — PDF/A, structure, accessibility, integrity, compare
pdf_rag — chunk (table-aware), index (LanceDB), semantic search, query-by-example, cross-document synthesis
pdf_analyze / pdf_redact / pdf_classify / pdf_dedupe / pdf_export — intelligence tools
pdf_do — autonomous agent that chains the tools from natural language
pdf_help / pdf_status / pdf_shutdown — meta tools
Related MCP server: pdf-mcp
Quick start
git clone https://github.com/sandraschi/pdf-mcp
cd pdf-mcp
uv sync
Copy-Item .env.example .env
.\start.ps1Dashboard: http://127.0.0.1:11130 · MCP/API: http://127.0.0.1:11131
Stack
Backend: Python 3.12, FastMCP 3.4.4, Starlette (HTTP), PyMuPDF, pypdf, pdfplumber, LanceDB, Prefab UI
Frontend: React 18, Vite 5, Tailwind CSS, Lucide, Framer Motion, Zustand, PDF.js, Playwright
Tooling: uv, bun, just, ruff, pyright, Biome, pre-commit
MCP tools
Tool | Operations |
| text, images, tables, metadata, fonts, links, outline |
| merge, split, rotate, reorder, delete_pages, compress, encrypt, decrypt, optimize |
| watermark, stamp, highlight, underline, header_footer, page_numbers, summary_box |
| list_fields, fill, flatten, export_data, auto_fill |
| to_markdown, to_images, to_html, from_html, from_markdown, from_images |
| pdfa, structure, accessibility, integrity, compare |
| chunk, index, search, similar, synthesize, list_documents, delete_index |
| intelligence |
| agentic chaining |
| meta |
Claude Desktop config
{
"mcpServers": {
"pdf-mcp": {
"command": "uv",
"args": ["--directory", "D:\\Dev\\repos\\pdf-mcp", "run", "python", "run_server.py"]
}
}
}For HTTP mode instead: uv run python run_server.py --mode http --port 11131 and connect over http://127.0.0.1:11131/mcp.
Configuration
See docs/CONFIGURATION.md. Key vars: MCP_MODE (stdio/http), MCP_PORT (11131), FRONTEND_PORT (11130), RAG_STORE_PATH, UPLOAD_DIR.
Webapp
Route | Page |
| Dashboard (KPIs, LLM availability, usage stats) |
| PDF.js viewer + OCR badge + compare mode + tool palette |
| Single operations + multi-step recipes + share links |
| LLM chat with PDF search + source citations |
| Discovery & logs |
Documentation
License
MIT
Available Tools
16 toolspdf_analyzeBRead-only
Detect whether a PDF has a text layer (digital) or is scanned, with layout stats.
Return Format
A dict with keys:
success: bool
pages: int
has_text_layer: bool - true when average chars per page >= 80
scanned: bool - low text + images present
chars_per_page: float
total_chars: int
image_count: int
layout_hint: str - digital | scanned | empty
per_page: list of {page, chars, images}
Examples
await pdf_analyze(path="scan.pdf") {"success": true, "pages": 5, "has_text_layer": false, "scanned": true, "chars_per_page": 12.4, "image_count": 5, "layout_hint": "scanned", "per_page": [...]}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description does add real behavioral value by disclosing the detection heuristics (has_text_layer when avg chars/page >= 80; scanned when low text plus images), but it says nothing about auth needs, file-path constraints, or failure behavior for invalid PDFs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence is front-loaded and tight, and the example is useful. However, the lengthy '## Return Format' block substantially duplicates the declared output schema, which is redundant length rather than earned content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, read-only diagnostic with an output schema and a worked example, an agent has everything needed to invoke it correctly. The only real gap is routing guidance against the many pdf_* siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (path), and schema description coverage is 100%, so the schema fully documents it. The description adds no syntax, path-format, or constraint detail for the parameter, making 3 the correct baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: detects whether a PDF has a text layer or is scanned, plus layout stats. This is clearly distinct from manipulation/export siblings, though it never names an alternative such as pdf_extract or pdf_classify to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to call this tool versus alternatives. Usage is only implied by the detection goal; there is no stated precondition (e.g. run before OCR/extraction) and no mention of siblings like pdf_extract or pdf_validate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_annotateA
Add annotations and markup to PDFs.
Watermark, stamp, highlight, underline, header/footer, and page numbers.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
watermark/stamp/header_footer/page_numbers: {path}
highlight: {path, occurrences}
underline: {path, occurrences} On failure: {success: False, error, error_type}.
Examples
await pdf_annotate(operation="watermark", path="report.pdf", text="CONFIDENTIAL", opacity=0.3) {"success": true, "path": ".../report_watermark_....pdf", "message": "Added watermark to report.pdf, saved to report_watermark_....pdf."}
await pdf_annotate(operation="highlight", path="report.pdf", search_text="revenue") {"success": true, "path": ".../report_highlight_....pdf", "occurrences": 3, "message": "Highlighted 3 occurrences of 'revenue' in report.pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | X position for stamp annotation. Default 50. | |
| y | No | Y position for stamp annotation. Default 50. | |
| page | No | Target page number (1-indexed). Applies to all pages if omitted. | |
| path | Yes | Path to the PDF file. | |
| text | No | Text content for watermark, stamp, header, or footer. | |
| color | No | Highlight color as hex. Default #FFFF00. | #FFFF00 |
| start | No | Starting page number. Default 1. | |
| footer | No | Footer text. | |
| header | No | Header text. | |
| opacity | No | Opacity for watermark. Default 0.3. | |
| position | No | Watermark position: center, top_left, top_right, bottom_left, bottom_right, tile. | center |
| font_size | No | Font size for header/footer/page numbers. Default 10. | |
| operation | Yes | ||
| image_path | No | Path to image file for image watermark. | |
| output_path | No | Output path. Auto-generated if omitted. | |
| search_text | No | Text to search for highlighting or underlining. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and openWorldHint=true, and the description goes beyond them by disclosing the auto-generated output path behavior (saving to report_watermark_...pdf), the success/error return shape, and occurrence counts for search-based operations. It does not address whether the original file is preserved or permission requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, then operations, return format, and examples using clear headings. The Return Format section partly duplicates the existing output schema, which is redundant, but the examples earn their space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 16 parameters and an output schema present, the description need not repeat return values, yet it does so. Its main gap is the operation-to-parameter contract: with seven enum operations sharing one flat parameter bag, the description only hints via examples which parameters apply to which operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 94%, so the baseline is 3, and the worked examples add genuine meaning by pairing specific operations with their relevant parameters (watermark with text/opacity, highlight with search_text). It still never states the mapping of which parameters are required or valid per operation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Add annotations and markup to PDFs') and enumerates the concrete operations (watermark, stamp, highlight, underline, header/footer, page numbers), which makes it distinguishable from content-removal siblings like pdf_redact. It stops short of naming a sibling it is not, so it does not reach the top of the scale.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied through the operation list and the two examples; there is no explicit statement of when to choose this tool over pdf_manipulate or pdf_redact, and no exclusions or prerequisites are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_classifyBRead-only
Guess the document type (invoice, report, contract, ...) and extract candidate fields.
Return Format
A dict with keys:
success: bool
doc_type: str
confidence: float (0-1)
fields: dict of detected fields (invoice_number, total, date, vendor)
reasons: list of matched signals
llm_refined: bool - whether the local LLM confirmed the guess
Examples
await pdf_classify(path="invoice_42.pdf") {"success": true, "doc_type": "invoice", "confidence": 0.75, "fields": {"invoice_number": "INV-42", "total": "1,240.00"}, "reasons": ["invoice(x2)"]}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. | |
| refine | No | Use the local LLM to refine the guess. Default true. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes a safe read operation, so the bar is lower. The description adds useful behavioral context: it is a heuristic guess with a confidence score, optional local-LLM refinement, and matched reasons. It does not disclose cost/latency implications of the LLM refinement or processing limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one sentence, followed by a compact return-format block and a concrete example. The structure is efficient and example-driven, though the verbose return-key listing partially duplicates what the output schema already provides.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be fully explained, yet the description is otherwise complete for invocation and interpretation. The notable gap is selection context: nothing tells the agent how this differs from sibling extraction/analysis tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so path and refine are already documented. The return-format section explains that llm_refined reflects the refine flag, which adds some cross-field meaning, but the description does not extend parameter semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (classify/guess) and resource (document type) with concrete examples of types and extracted fields, so an agent understands the operation. It does not, however, differentiate itself from close siblings like pdf_extract or pdf_analyze, which also surface document fields.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance or reference to alternatives. With siblings pdf_extract, pdf_analyze, and pdf_validate present, the agent gets no signal about when classification is preferable to generic extraction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_convertB
Convert between PDF and other formats.
PDF to/from Markdown, HTML, and images.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
to_markdown: {markdown, pages}
to_images: {images: [{page, path, width, height}]}
to_html: {html}
from_html/from_markdown/from_images: {path, pages} On failure: {success: False, error, error_type}.
Examples
await pdf_convert(operation="to_markdown", path="report.pdf") {"success": true, "markdown": "# Report...", "pages": 3, "message": "Converted report.pdf to markdown (3 pages)."}
await pdf_convert(operation="from_markdown", markdown="# Hello") {"success": true, "path": ".../output_from_markdown_....pdf", "pages": 1, "message": "Created PDF from markdown (1 pages), saved to output_from_markdown_....pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| dpi | No | DPI for image output. Default 200. | |
| fmt | No | Image format (png, jpeg). Default png. | png |
| html | No | HTML content for from_html operation. | |
| path | No | Path to the PDF file. Required for to_* operations. | |
| paths | No | Image paths for from_images operation. | |
| markdown | No | Markdown content for from_markdown operation. | |
| operation | Yes | ||
| output_dir | No | Output directory for to_images operation. | |
| output_path | No | Output path. Auto-generated if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and openWorldHint=true, so the description does carry some burden. It discloses the failure shape ({success: False, error, error_type}) and that outputs are written to disk with an auto-generated name, which is useful. It does not state file-write permissions, overwrite behavior, or where output lands when output_dir/output_path are omitted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a one-line purpose followed by return-format and example sections that are skimmable and well-labeled. Slightly padded because an output schema already exists, making the return-format section partially redundant, but the worked examples genuinely aid correct invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-operation tool, the description names every operation, shows two worked calls, and explains both success and failure payloads. Since an output schema exists, return values need not be restated; the remaining gap is the absence of operation-to-parameter mapping (e.g. from_images needing paths).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 89%, so the schema already documents path, paths, html, markdown, dpi, fmt, output_dir, and output_path. The description adds no per-parameter syntax or format detail beyond that, so the baseline 3 applies even though the call examples show realistic argument combinations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Convert between PDF and other formats'), enumerates the target formats, and the operation enum makes the directionality explicit. It does not, however, distinguish itself from siblings such as pdf_export, pdf_extract, or pdf_do, which an agent must choose among from a 16-tool family.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use pdf_convert versus pdf_export or pdf_extract, nor on prerequisites such as whether the PDF must already exist on disk. Usage is only implied through the operation enum, leaving the selection decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_dedupeBRead-only
Detect exact and near-duplicate PDFs by content fingerprint.
Return Format
A dict with keys:
success: bool
files: list of input file names
exact_duplicates: [{sha, count, files}]
near_duplicates: [{a, b, similarity}]
Examples
await pdf_dedupe(paths=["a.pdf", "b.pdf"]) {"success": true, "files": ["a.pdf", "b.pdf"], "exact_duplicates": [], "near_duplicates": [{"a": "a.pdf", "b": "b.pdf", "similarity": 0.92}]}
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | List of PDF paths to check for duplicates. | |
| threshold | No | Similarity threshold 0-1. Default 0.85. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes the safety profile, so the bar is lower. The description adds the detection mechanism (content fingerprint) and the exact shape of the result keys, which is useful context, but says nothing about performance on large file sets or how near-duplicate similarity is computed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose, then a structured return-format block and a runnable example. Every section earns its place except the return-format block, which partly duplicates the existing output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with an output schema and readOnly annotation, the description covers purpose, output keys, and a concrete example. The main gap is the absence of any when-to-use guidance, which is not offset elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with both 'paths' and 'threshold' documented in the schema (including the 0.85 default and the 0-1 range). The description adds no parameter syntax or format detail beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (detect) and resource (PDFs) with a clear scope: exact and near-duplicate matching via content fingerprint. It is unambiguous and distinct from every sibling tool, none of which do duplicate detection, though it doesn't explicitly reference those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never states when to use this tool, when not to, or what alternatives exist. Usage is only implied by the purpose statement and the example, leaving the agent to infer the trigger conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_doA
Chain the PDF tools autonomously to complete a natural-language task.
Requires a local LLM (Ollama or LM Studio) or a client that supports MCP sampling. The LLM plans up to 6 tool calls from the pdf_* surface, the server answer. pdf_do cannot call itself or pdf_shutdown.
Return Format
A dict with keys:
success: bool
answer: str - final natural-language answer
steps: list of {tool, args, result} execution records On failure: {success: False, error}.
Examples
await pdf_do(task="Summarize this report and check it for PII.", path="report.pdf") {"success": true, "answer": "The report covers Q3 results... 3 PII hits found.", "steps": [{"tool": "pdf_export", ...}]}
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Path to a PDF file if the task targets one. | |
| task | Yes | Natural-language task to perform with the PDF tooling. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real behavioral context beyond annotations: it depends on an external LLM to plan, is capped at 6 tool calls, and is explicitly non-recursive (cannot invoke itself or pdf_shutdown). Annotations already flag readOnlyHint=false and openWorldHint=true, and the description's LLM-dependency and planning behavior are non-obvious traits worth disclosing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose, then organizes prerequisites, return format, and an example into clear sections with little redundancy. The prerequisite sentence contains a dangling fragment ('the server answer') that slightly hurts polish but doesn't obscure meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a non-trivial orchestrator this covers the dependency requirements, recursion limits, return structure, and a failure shape, plus a worked example. It is complete enough that an agent can invoke it correctly, though it could say more about what happens when no LLM/sampling is available.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters (task, path) are already documented in the schema. The description and example add slight practical context (path targets a PDF, task is a natural-language instruction) but nothing beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource: it autonomously chains the pdf_* tools to fulfill a natural-language task. This clearly differentiates it from the individual sibling tools (pdf_export, pdf_extract, etc.) since it is the orchestration layer above them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete prerequisites (needs a local Ollama/LM Studio LLM or MCP-sampling client) and explicit boundaries (max 6 planned calls, cannot call itself or pdf_shutdown). It does not state when to prefer pdf_do over calling the pdf_* tools directly, so routing guidance is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_exportB
Build a reusable document brief (markdown or JSON) with headings, key terms, and optional summary.
Return Format
A dict with keys:
success: bool
path: str - brief file path
pages: int
summary: str | None
Examples
await pdf_export(path="report.pdf", format="markdown") {"success": true, "path": ".../report_brief.md", "pages": 12, "summary": "..."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. | |
| format | No | Output format. Default markdown. | markdown |
| include_summary | No | Append an LLM summary when available. Default true. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and openWorldHint=true, so the write/no-side-effect profile is partly conveyed structurally, and the description adds that a brief file is written (via path) with an appended LLM summary when available. It does not state overwrite behavior, required permissions, or that the summary step may be costly/non-deterministic, so credit is moderate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose and keeps the return-format and example sections terse and skimmable. Slight redundancy in restating return keys that an output schema already covers.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, yet the description restates them, which is harmless filler rather than a gap. For a file-writing tool the main missing context is write/permission and overwrite semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters (path, format, include_summary) are already well documented; the description only echoes format options and the optional summary. Nothing beyond the schema is added, matching the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ("Build") and resource ("reusable document brief") plus the artifact's content (headings, key terms, summary). It does not, however, differentiate clearly from siblings like pdf_extract or pdf_analyze, which also derive content from a PDF.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, prerequisites, or named alternatives are given, despite 15 sibling tools in the pdf_* family. The agent must infer the tool's niche on its own.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_extractBRead-only
Extract content and metadata from a PDF.
Supports text, images, tables, metadata, fonts, links, and outline extraction through a single portmanteau tool.
Args are validated and documented via Annotated fields on the signature.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
text: {text, pages, page_count}
images: {images: [{page, index, width, height, path, ext}]}
tables: {tables: [{page, rows, cols, headers, data}]}
metadata: {metadata: {...}}
fonts: {fonts: [{name, type, encoding, embedded, size}]}
links: {links: [{page, uri, page_target, rect}]}
outline: {outline: [{title, level, page, children}]} On failure: {success: False, error, error_type}.
Examples
await pdf_extract(operation="text", path="report.pdf", pages="1-3") {"success": true, "text": "...", "pages": 3, "page_count": 12, "message": "Extracted 3 pages of text from report.pdf."}
await pdf_extract(operation="metadata", path="report.pdf") {"success": true, "metadata": {"title": "Report", ...}, "message": "Extracted metadata from report.pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. | |
| pages | No | Optional page range (e.g. '1-5,7,9-12'). All pages if omitted. | |
| operation | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read operation. The description adds the return dict shape and the failure shape ({success: False, error, error_type}), which is useful, but since an output schema exists the return-format detail is partly redundant and no permissions, limits, or edge-case behavior are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, then operations, return format, and examples follow in a clear hierarchy. It runs long and duplicates the output schema in the Return Format section, but each block is scannable and relevant for a portmanteau tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the return-value documentation is not strictly needed, and the operation list makes invocation clear. However, against 16 sibling tools the description gives no routing guidance, leaving a real gap in knowing when this tool is the right choice.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%; the operation enum has no schema description, but the description enumerates its values (text, images, tables, metadata, fonts, links, outline), compensating for that gap. path and pages are already documented in the schema, so the description does its job where coverage is missing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Extract content and metadata from a PDF') and enumerates the seven extraction modes, so the agent understands the tool's scope precisely. It does not explicitly distinguish itself from siblings like pdf_rag or pdf_analyze, which prevents a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to choose pdf_extract over the many siblings (pdf_rag, pdf_analyze, pdf_convert, etc.) or when not to use it. 'Single portmanteau tool' implies consolidation but provides no decision criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_formsCRead-only
Handle interactive form fields.
List, fill, flatten, export, and auto-fill (LLM-guided) PDF form fields.
Return Format
A dict with keys:
success: bool
message: str - human-readable summary
operation-specific keys:
list_fields: {fields: [{name, type, value, page, rect}]}
fill/flatten: {path}
export_data: {data: {field_name: value}}
auto_fill: {path, filled, missing} On failure: {success: False, error, error_type}.
Examples
await pdf_forms(operation="list_fields", path="form.pdf") {"success": true, "fields": [{"name": "name", "type": "text", "value": "", "page": 0, "rect": [...]}], "message": "Found 1 form fields in form.pdf."}
await pdf_forms(operation="fill", path="form.pdf", fields={"name": "Ada"}) {"success": true, "path": ".../form_fill_....pdf", "message": "Filled 1 form fields in form.pdf, saved to form_fill_....pdf."}
await pdf_forms(operation="auto_fill", path="form.pdf", source="source.pdf") {"success": true, "path": ".../form_autofill_....pdf", "filled": 3, "missing": [], "message": "Auto-filled 3 fields in form.pdf from source.pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. | |
| text | No | Source text driving auto_fill (alternative to source). | |
| fields | No | Dict of field_name: value for fill operation. | |
| source | No | Source PDF path whose text drives auto_fill. | |
| operation | Yes | ||
| output_path | No | Output path. Auto-generated if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, yet the description states the tool fills, flattens, and auto-fills forms, writing new PDFs to output_path (fill/flatten return {path}, auto_fill returns {path, filled, missing}). Writing files modifies the environment, so the description contradicts the read-only annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and an operation list, then cleanly sectioned into Return Format and Examples with headers. It is a bit long and the return-format block duplicates the output schema, but every part is readable and none is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter, multi-operation tool the description covers the operation set, key inputs, success/failure shapes, and worked examples. Since an output schema exists, the return-format section is redundant but not harmful; the main gap is the absence of permission/when-to-use context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high (83%) and the schema already documents path, fields, source, text, and output_path with their roles. The description reiterates the operations and return shape but adds no new parameter meaning (e.g., fill value typing, flatten vs fill interaction) beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It names a specific resource (PDF form fields) and enumerates the concrete operations (list, fill, flatten, export, auto-fill) which map cleanly onto the operation enum. However, it does nothing to distinguish this from siblings such as pdf_annotate, pdf_manipulate, or pdf_export, so the agent must infer boundaries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use / when-not-to-use guidance and no named alternatives among the many pdf_* siblings. The only hint is that auto_fill is 'LLM-guided', with no prerequisites, permissions, or conditions noted for choosing a given operation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_helpARead-only
List available tools and get usage help for pdf-mcp.
Return Format
A dict with keys:
success: bool
message: str - human-readable summary
data: list of tools with name, description, and input schema, or detailed help for a single tool when tool_name is provided.
Examples
await pdf_help() {"success": true, "message": "8 tools available.", "data": [{"name": "pdf_extract", ...}]}
await pdf_help(tool_name="pdf_extract") {"success": true, "message": "Help for pdf_extract.", "data": {...}}
| Name | Required | Description | Default |
|---|---|---|---|
| tool_name | No | Name of a tool to get detailed help for. Lists all tools if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true is consistent with a help/discovery operation, and the description goes beyond the annotation by documenting the return contract (success/message/data with tool names, descriptions, and input schemas). It does not mention latency or authentication characteristics, but for a read-only introspection tool the disclosure is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, followed by a compact return-format block and two concrete examples. The examples earn their place for a help tool since they demonstrate both the no-arg and arg call shapes, though the section could be trimmed slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be re-explained, and the annotation covers safety. The description still supplies the response shape and examples, making the definition complete for a zero-required-parameter help tool; no prerequisites or edge cases are omitted that would block correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single parameter already documents 'Name of a tool to get detailed help for. Lists all tools if omitted.' The description restates this rather than adding syntax or format depth, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource pair: lists available tools and returns usage help for the pdf-mcp server, with an optional drill-down for a single tool. It is unmistakably the meta/discovery tool, distinguishable at a glance from all named siblings like pdf_extract or pdf_export.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description and worked examples make the when-to-use clearly implied: call with no arguments to enumerate tools, call with tool_name for detailed help. It states the selection condition for the parameter ('Lists all tools if omitted') but does not explicitly frame when an agent should prefer this help lookup over just reading a tool's own schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_manipulateA
Modify PDF structure and properties.
Merge, split, rotate, reorder, delete pages, compress, encrypt/decrypt, and optimize PDFs.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
merge: {path, pages}
split: {files: [path, ...]}
rotate/reorder/delete_pages/encrypt/decrypt: {path}
compress: {path, original_size, compressed_size}
optimize: {path, original_size, optimized_size} On failure: {success: False, error, error_type}.
Examples
await pdf_manipulate(operation="merge", path="a.pdf", paths=["a.pdf", "b.pdf"]) {"success": true, "path": ".../merged_....pdf", "pages": 4, "message": "Merged 2 PDFs into merged_....pdf (4 pages)."}
await pdf_manipulate(operation="rotate", path="report.pdf", angle=90) {"success": true, "path": ".../report_rotate_....pdf", "message": "Rotated report.pdf by 90 degrees, saved to report_rotate_....pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. Ignored for merge. | |
| angle | No | Rotation angle in degrees. Default 90. | |
| pages | No | Page range string (e.g. '1-5,7,9-12'). For rotate operation. | |
| paths | No | List of PDF paths to merge. Only for merge operation. | |
| ranges | No | Split ranges as list of [start, end] pairs (1-indexed). | |
| quality | No | Compression quality 1-100. Default 85. | |
| password | No | Password for encrypt/decrypt operations. | |
| new_order | No | New page order (1-indexed list). For reorder operation. | |
| operation | Yes | ||
| page_list | No | List of page numbers to delete. For delete_pages operation. | |
| output_dir | No | Output directory for split operation. | |
| output_path | No | Output path. Auto-generated if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and openWorldHint=true, so the description carries real weight and does so: it discloses that outputs are written to auto-generated new files (e.g., 'saved to report_rotate_....pdf') rather than mutating in place, and it documents failure shape via {success: False, error, error_type}. It does not mention permission requirements or that encrypt/decrypt need a password, but the operation-level output mapping is genuinely additive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loading is good and the headers make it scannable, but the entire '## Return Format' section duplicates the output schema that already exists, so a large share of the text does not earn its place. The two examples are useful and worth keeping; the key-by-key return listing is not.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter, nine-operation tool with an output schema and strong schema coverage, the description supplies the operation inventory and concrete invocation examples, which is close to sufficient. The remaining gap is the absence of any guidance on choosing among sibling PDF tools and on output_path vs output_dir behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 92%, so the baseline is 3, and the worked examples push it higher by showing real parameter combinations (operation+path+paths for merge, operation+path+angle for rotate). The return-format section also ties each operation to the fields it consumes, which the schema does not do in one place.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Modify PDF structure and properties') and then enumerates all nine concrete operations, which cleanly separates it from siblings like pdf_convert, pdf_extract, pdf_annotate, and pdf_redact. An agent can identify the tool's scope without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to choose pdf_manipulate over pdf_convert, pdf_do, or pdf_annotate, nor does it state prerequisites or when-not to use it. The operation list implies usage, but no routing guidance or exclusions are given despite 15 sibling tools existing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_ragCRead-only
Build and query a RAG index over PDF content.
Chunks, indexes, and semantically searches PDF text via LanceDB. Tables are indexed as structured chunks (section='table'). Supports query-by-example and cross-document synthesis.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
chunk: {chunks, doc_id}
index: {chunks_indexed, doc_id}
search: {results: [{doc_id, chunk_id, page_num, section, source_file, text, _distance}]}
similar: same shape as search (seeded by a text snippet)
synthesize: {groups: [{doc_id, source_file, hits, snippet}], summary?}
list_documents: {documents: [{doc_id, chunk_count}]}
delete_index: {} On failure: {success: False, error, error_type}.
Examples
await pdf_rag(operation="chunk", path="book.pdf", strategy="recursive", chunk_size=1000) {"success": true, "chunks": 42, "doc_id": "a1b2c3d4e5f6", "message": "Chunked book.pdf (300 pages) into 42 chunks with recursive strategy."}
await pdf_rag(operation="search", query="quarterly revenue") {"success": true, "results": [{...}], "message": "Found 3 results for 'quarterly revenue'."}
await pdf_rag(operation="similar", text="The sky was unusually clear that night.") {"success": true, "results": [{...}], "message": "Found 2 similar passages."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Path to the PDF file. Required for chunk, index operations. | |
| text | No | Source text snippet for similar (query-by-example) operation. | |
| limit | No | Max search results. Default 10. | |
| query | No | Search query for search / synthesize operations. | |
| doc_id | No | Document ID for delete_index operation. | |
| overlap | No | Chunk overlap in characters. Default 200. | |
| strategy | No | Chunking strategy: recursive, fixed. Default recursive. | recursive |
| operation | Yes | ||
| chunk_size | No | Target chunk size in characters. Default 1000. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation declares readOnlyHint=true, yet the tool's own operation list includes write/mutating operations: chunk and index create LanceDB tables and delete_index destroys a stored index. The description directly contradicts the read-only annotation, leaving the agent misinformed about side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then return format, then concrete examples with headers. Well organized, though the explicit return-format block is partly redundant given an output schema exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-operation, 9-parameter tool the operation coverage and return shapes are reasonably complete, and an output schema exists. The main gap is the unresolved read-only vs. mutating/destructive confusion introduced by the annotation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 89%, so the schema already documents path, text, limit, query, doc_id, overlap, strategy, and chunk_size. The description adds operational context (which operation seeds from a snippet) but little syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb+resource: 'Build and query a RAG index over PDF content.' It clearly conveys the dual build/query nature. It does not, however, differentiate itself from the many sibling PDF tools (pdf_analyze, pdf_extract) that an agent might otherwise choose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description enumerates operations but never states when to use pdf_rag versus the 15 sibling tools, nor any prerequisite like 'you must chunk/index before searching.' Usage must be inferred from operation names alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_redactADestructive
Blacken sensitive content in a PDF by terms and/or PII patterns.
Return Format
A dict with keys:
success: bool
path: str - output PDF path
occurrences: int - number of regions redacted On failure: {success: False, error}.
Examples
await pdf_redact(path="report.pdf", pii=True) {"success": true, "path": ".../report_redact_....pdf", "occurrences": 7}
await pdf_redact(path="report.pdf", terms=["Acme Corp"]) {"success": true, "path": ".../report_redact_....pdf", "occurrences": 3}
| Name | Required | Description | Default |
|---|---|---|---|
| pii | No | Redact PII (email, phone, IBAN, card, SSN, IP). Default false. | |
| path | Yes | Path to the PDF file to redact. | |
| terms | No | Exact phrases to blacken. | |
| output_path | No | Output path. Auto-generated if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true, so the safety profile is covered structurally. The description adds the return contract (success/path/occurrences and the failure shape), which is useful, but says nothing about permissions, whether the source file is modified, or file-size/page limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in a single sentence, followed by a compact return contract and two examples that each earn their place. The Return Format section partially duplicates the existing output schema, which is the only mild redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter mutation tool with full schema coverage and an output schema, the description is sufficient: purpose, return contract, and worked examples are all present. It could be richer on side effects (whether the original PDF is preserved) but nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented in the schema and the baseline is 3. The description's mention of 'terms and/or PII patterns' and the examples reinforce how the parameters combine, but add no syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Blacken sensitive content in a PDF') plus the two mechanisms ('terms and/or PII patterns'), which cleanly separates it from every other pdf_* sibling such as pdf_annotate or pdf_extract. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The two examples imply the two modes (pii=True for pattern-based redaction, terms=[...] for exact phrases), which is useful implied guidance, but there is no explicit statement of when to choose this tool over pdf_annotate or pdf_manipulate, and no preconditions or exclusions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_shutdownBDestructive
Gracefully shut down the pdf-mcp server.
Return Format
A dict with keys:
success: bool
message: str - shutdown confirmation
Examples
await pdf_shutdown() {"success": true, "message": "Shutting down pdf-mcp."}
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No | Optional shutdown reason. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The destructiveHint=true annotation already flags this as destructive, so the description needn't restate that. It does add value by specifying the shutdown is 'graceful,' implying an orderly stop rather than a hard kill, but it omits what actually gets destroyed (other sessions, in-flight jobs) and whether the action is reversible.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in a single clear sentence, which is good. However, the Return Format block and the example duplicate what the existing output schema already conveys, so several lines do not earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity, zero-required-parameter tool with an output schema present, the description is minimally adequate once return values are excluded. It nonetheless omits the operational impact of shutting down the server, which is the main thing an agent needs before invoking a destructive action.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single optional 'reason' parameter is documented in the schema, so the baseline is 3. The description never mentions the 'reason' parameter and adds no semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('shut down') and resource ('the pdf-mcp server'), clearly distinguishing this from every sibling tool that manipulates or exports PDFs. An agent immediately knows this terminates the server rather than doing document work.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says what the tool does but offers no when-to-use, when-not-to-use, or alternative guidance. It does not warn when shutdown is appropriate, whether other active operations are affected, or how to reverse/restart, leaving usage entirely to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_statusARead-only
Report server status, version, uptime, and registered tool count.
Return Format
A dict with keys:
success: bool
server: str - server name
version: str - server version
uptime_seconds: int
tool_count: int
mode: str - stdio or http
Examples
await pdf_status() {"success": true, "server": "pdf-mcp", "version": "0.1.0", "uptime_seconds": 42, "tool_count": 8, "mode": "http"}
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description goes beyond that with useful context: the exact fields returned, the meaning of the 'mode' value (stdio or http), and a concrete worked example, which tells the agent what a healthy response looks like.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence and the rest is scannable structure. The 'Return Format' block partly duplicates the output schema, which is slight redundancy, but the example adds concrete value rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-argument, read-only diagnostic tool this is complete: the agent knows what it does, what comes back, and has a runnable example. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is an empty object with additionalProperties=false, so there is nothing for the description to disambiguate. The provided example call (await pdf_status()) reinforces that no arguments are needed, which is the correct baseline for a 0-param tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Report') and resource ('server status') and enumerates exactly what is reported: version, uptime, and registered tool count. No sibling in the pdf_* family serves this diagnostic role, so the agent can route to it unambiguously from the name and first sentence alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: an agent can infer this is the health/diagnostic call, but there is no explicit when-to-use, no prerequisites, and no comparison to alternatives such as pdf_help. It is adequate but leaves the agent to infer the trigger condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pdf_validateARead-only
Audit PDF quality and compliance.
PDF/A, structure, accessibility, integrity, and comparison checks.
Return Format
A dict with keys:
success: bool - whether the operation succeeded
message: str - human-readable summary
operation-specific keys:
pdfa: {is_pdfa, details}
structure: {has_tags, headings, paragraphs, issues}
accessibility: {score (0-100), issues}
integrity: {intact, pages_readable, warnings}
compare: {same_page_count, text_similarity, diffs} On failure: {success: False, error, error_type}.
Examples
await pdf_validate(operation="accessibility", path="report.pdf") {"success": true, "score": 75, "issues": [...], "message": "Accessibility score: 75/100 for report.pdf. 0 errors, 1 warnings."}
await pdf_validate(operation="compare", path_a="a.pdf", path_b="b.pdf") {"success": true, "same_page_count": true, "text_similarity": 0.98, "diffs": [], "message": "Comparison: same page count, 98.0% text similarity between a.pdf and b.pdf."}
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Path to the PDF file. Ignored for compare. | |
| path_a | No | First PDF path for compare operation. | |
| path_b | No | Second PDF path for compare operation. | |
| operation | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | No | Human-readable summary |
| success | No | Whether the operation succeeded |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered, but the description adds meaningful behavioral context beyond that: the exact success/failure shape ({success: False, error, error_type}) and operation-specific result keys. It does not discuss performance, file-size limits, or what 'integrity' warnings imply, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose, then clearly labeled 'Return Format' and 'Examples' sections; headers make it scannable. It is somewhat long because the operation-key dictionary is enumerated, which the output schema arguably already covers, so a small amount of redundancy keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-mode validation tool with a full output schema and read-only annotations, the description covers purpose, all operations, failure handling, and usage examples. An agent has everything needed to select the right operation and construct a correct call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The per-operation result mapping and the two examples clarify that 'compare' requires path_a/path_b while other operations use 'path', adding real meaning beyond the 75%-covered schema. The schema descriptions still carry some of the load (e.g. 'Ignored for compare'), so this is helpful rather than fully self-sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Audit PDF quality and compliance') and enumerates the five concrete check categories (PDF/A, structure, accessibility, integrity, comparison). This is far more than a restatement of the name. It stops short of distinguishing itself from the sibling pdf_analyze, which likely overlaps in scope, so it does not earn a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The enumerated operations imply what each mode is for, and the example for 'compare' shows when path_a/path_b are needed, giving implicit usage guidance. However, there is no explicit when-to-use / when-not-to-use statement and no routing away from siblings like pdf_analyze. Adequate but with a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
16 tool updates
v0.2.1- First observed
pdf_analyze - First observed
pdf_annotate - First observed
pdf_classify - First observed
pdf_convert - First observed
pdf_dedupe - First observed
pdf_do - First observed
pdf_export - First observed
pdf_extract - First observed
pdf_forms - First observed
pdf_help - First observed
pdf_manipulate - First observed
pdf_rag - First observed
pdf_redact - First observed
pdf_shutdown - First observed
pdf_status - First observed
pdf_validate
TDQS
Scored across 16 tools
Most tools target clearly distinct operations (extract, convert, annotate, forms, redact, classify, dedupe, validate). A few boundaries blur: pdf_analyze vs pdf_validate both perform structural audits, and pdf_export's markdown brief overlaps with pdf_convert's to_markdown and pdf_extract's text output.
All 16 tools use a consistent pdf_ snake_case prefix with verb-style names (pdf_extract, pdf_convert, pdf_annotate, pdf_validate). Minor deviations: pdf_rag uses a noun/acronym and pdf_do is a vague verb, but the overall pattern is predictable.
16 tools for a full PDF processing suite is reasonable; each operation (extract, convert, manipulate, annotate, forms, RAG, redact, classify, dedupe, validate, analyze, export) earns its place alongside help/status/shutdown infrastructure. Slightly heavy but well within scope.
Broad lifecycle coverage: read, transform, annotate, secure, validate, and even semantic indexing. Notable gap: pdf_analyze detects scanned PDFs but no OCR tool exists to make them usable, a common follow-on for a PDF domain. Otherwise the surface is robust with no major dead ends.
Maintenance
Related MCP Connectors
Hosted MCP server: convert PDFs to clean, LLM-ready Markdown with tables, formulas and OCR.
Document-to-Markdown MCP server — convert PDF, Office and HTML into LLM-ready Markdown.
Document conversion MCP server: PDF to Markdown, image OCR, spreadsheet parsing.
MCP server for the PDFGate API. Generate PDFs, manage documents and handle e-signatures.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceEnables comprehensive PDF analysis and manipulation including page size analysis, chapter extraction, splitting, compression, merging, and conversion to images. Provides both MCP server interface for AI assistants and Streamlit web interface for direct user interaction.-
- AlicenseAqualityCmaintenanceAn MCP server for reading, rendering, and searching PDF files, specifically optimized for LLMs to extract text, tables, and technical diagrams. It enables metadata retrieval, multi-format text extraction, and page-to-image rendering using PyMuPDF.578MIT
- 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

pymupdf4llm-mcpofficial
AlicenseNot gradedqualityCmaintenanceMCP server for exporting PDF to markdown, optimized for LLM consumption.5,254 PyPI71AGPL 3.0