Skip to main content
Glama
sandraschi

pdf-mcp

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
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", ...}]}

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."}

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."}

pdf_extractB

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."}

pdf_formsC

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."}

pdf_analyzeB

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": [...]}

pdf_redactA

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}

pdf_classifyB

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)"]}

pdf_dedupeB

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}]}

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": "..."}

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."}

pdf_helpA

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": {...}}

pdf_statusA

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"}

pdf_shutdownB

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."}

pdf_ragC

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."}

pdf_validateA

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."}

Prompts

Interactive templates invoked by user choice

NameDescription
analyze_documentAnalyze a PDF: type, OCR readiness, and a summary.
summarize_documentSummarize a PDF into a reusable brief.
extract_tablesExtract all tables from a PDF.
rag_questionAsk a question across the indexed PDFs.
redact_reviewCheck a PDF for PII and redact it.
compare_documentsCompare two PDFs and summarize the differences.

Resources

Contextual data attached and managed by the client

NameDescription
server_configServer configuration snapshot.
server_statusLive server status (tool count, uptime).
pdf-expert/SKILL.mdpdf-mcp Skill
pdf-expert/_manifestFile listing for pdf-expert
Prefab Renderer (pdf_analyze)
Prefab Renderer (pdf_classify)
Prefab Renderer (pdf_dedupe)
Prefab Renderer (pdf_help)
Prefab Renderer (pdf_status)

TDQS

A3.5/5.0

Scored across 16 tools

Disambiguation4/5

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.

Naming Consistency4/5

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.

Tool Count4/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues