# io.github.benbergner/benspdf (pypi · benspdf-mcp)

Read PDFs locally: text, pages, metadata, scan detection, layout, permissions, render, OCR.

- Trust score: 67/100 (medium)
- Change this week: +19
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-20

## Components

- pypi · `benspdf-mcp`: 67/100 (this document), [markdown](https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp.md), [page](https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp)

## Channel facts

- Registry: `pypi`
- Package: `benspdf-mcp`
- Version: `0.3.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-20.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs setuptools.build_meta at install time, a recognised native-build step with no shell scripting around it.
  - 1 of 32 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 6 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 68/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 2674 tokens (~222/item across 12 items; 12 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 71/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
  - Structured output schemas are declared (92% of tools); any adoption earns full credit.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "discard" implies "delete" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 13 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the io.github.benbergner/benspdf MCP server?

io.github.benbergner/benspdf runs locally as a PyPI package, launched with uvx benspdf-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add benbergner-benspdf -- uvx benspdf-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "benbergner-benspdf": {
      "command": "uvx",
      "args": [
        "benspdf-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "benbergner-benspdf": {
      "command": "uvx",
      "args": [
        "benspdf-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add benbergner-benspdf -- uvx benspdf-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "benbergner-benspdf": {
      "type": "local",
      "command": [
        "uvx",
        "benspdf-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add benbergner-benspdf --command uvx --arg benspdf-mcp
```

### Hermes

```yaml
mcp_servers:
  benbergner-benspdf:
    command: "uvx"
    args: ["benspdf-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "benbergner-benspdf": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "benspdf-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add benbergner-benspdf -t stdio -c uvx -a benspdf-mcp
```

### Other

```json
{
  "mcpServers": {
    "benbergner-benspdf": {
      "command": "uvx",
      "args": [
        "benspdf-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-20 (score 67, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-18 (score 66, +1)

No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-16 (score 65, +1)

No change was recorded against any check on this day. Stability & Change Management went from 10 to 13. That category is still filling its 30-day observation window: 3 days of observed history at the previous scan, 4 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-14 (score 64, +16)

- [security improvement] Malware scan: unverified → pass

### 2026-09-13 (score 48, +1)

- [security improvement] Malware scan: unverified → pass
- [functional regression] Schema quality: 201 → 222
- [functional regression] Schema quality: 2018 → 2347
- [functional improvement] Stability: unverified → 0.03
- [functional] Package version: 0.1.1 → 0.3.0
- [functional] Package version: 0.1.1 → 0.2.0

### 2026-09-12 (score 47)

First indexed and scored.

## MCP tools (12)

### `export` (~243 tokens)

Save one or more results to a real location on disk.

The only tool that writes to the user's filesystem, so call it once at the
end, when they have said where the output should go. Never hand an artifact
id back as if it were a finished file; artifacts expire.

Args:
    refs: Artifact id, or list of artifact ids, to export.
    dest: Where to write. For a single artifact this may be a full file
        path. For several artifacts, or when `name` is given, this is a
        directory and is created if missing.
    name: Filename template used when writing into a directory.
        Placeholders: {n} 1-based index (e.g. "page_{n:03d}{ext}"),
        {ext} extension, {id} artifact id, {stem} id without extension.
        Defaults to "{n:03d}{ext}".
    overwrite: Replace existing files instead of failing. Defaults to
        False so nothing is destroyed by accident.

Input parameters:

- `dest` (string, required)
- `name`
- `overwrite` (boolean)
- `refs` (required)

Output parameters:

- `result` (object)

### `list_artifacts` (~69 tokens)

List recent temporary artifacts in the workspace, newest first.

Useful when you have lost track of an artifact id from earlier in the
conversation, so you can find it again instead of redoing the work.

Args:
    limit: Maximum number of artifacts to return.

Input parameters:

- `limit` (integer)

Output parameters:

- `result` (object)

### `discard` (~79 tokens)

Delete temporary artifacts from the workspace now.

Only accepts artifact ids, never file paths, so this cannot delete the
user's own files. Artifacts expire on their own, so this is only needed
when the user explicitly asks to clean up.

Args:
    refs: Artifact id, or list of artifact ids, to delete.

Input parameters:

- `refs` (required)

Output parameters:

- `result` (object)

### `pdf_page_count` (~78 tokens)

Count the pages in a PDF. Answers "how many pages is this?".

Reads only the document's page tree, so it stays cheap on large files. It
does not read page text, page sizes, or document properties.

Args:
    ref: PDF file path, or a workspace artifact id.

Input parameters:

- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_metadata` (~194 tokens)

Read a PDF's document properties: title, author, dates, producer, keywords.

Answers "who made this, when, and with what". It does not count pages (use
pdf_page_count) and says nothing about whether the pages hold readable text
(use pdf_check_text).

A PDF can store these fields in two independent places, the legacy Info
dictionary and an XMP packet, and the two often disagree. The normalized
answer is at the top level, preferring XMP, with `sources` naming the store
each value came from and `conflicts` listing every field where the two differ,
both values included. Both stores also come back verbatim as `info` and `xmp`.
When `has_conflicts` is true, say so rather than quoting one value as fact.

Args:
    ref: PDF file path, or a workspace artifact id.

Input parameters:

- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_check_text` (~229 tokens)

Check whether a PDF has a text layer, looks scanned, or needs OCR.

Answers "can I read this, or is it a picture of a document?". Worth running
before extracting text from a file you have not seen.

\`verdict` is "text", "scanned", "mixed", or "no_text" — the last meaning
nothing readable but nothing scan-like either, so blank, vector-only, or
illustrated pages that OCR cannot help. `needs_ocr` follows from it, `summary`
is a sentence worth quoting, and the per page evidence behind the verdict
comes back alongside, including each page's `image_coverage` (the largest
image's share of the page area).

Samples up to 10 pages spread across the document, so a true `sampled` means
the answer is an estimate for the pages in between. It does not return the
text (use pdf_extract_text) and it does not run OCR.

Args:
    ref: PDF file path, or a workspace artifact id.

Input parameters:

- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_extract_text` (~327 tokens)

Read the text of a PDF that has one, page by page.

The cheap and exact way to read a document: milliseconds a page, and the
characters are the ones the file holds. Prefer it to pdf_ocr, which is for
pages carrying no text, and to pdf_render_pages, which costs an image a page.
pdf_check_text says which path a file needs; page numbers come back with the
text, so quote page 8 rather than "the document".

A long document arrives in ranges: one call returns about 50,000 characters
and names the pages it did not reach, so when `truncated`, do what the summary
says. `output="txt"` writes the whole extraction to an artifact and returns
the counts alone, which is the way to read a book.

Text on a `text_suspect` page came back partly undecodable, because the fonts
carry no character map: say so rather than quoting it, and look at the page
with pdf_render_pages.

Args:
    ref: PDF file path, or a workspace artifact id.
    pages: Which pages: "1-10", "3", "1,5,9-12" or "all". Defaults to all.
    output: "text", "txt" for the text as an artifact, or "both".
    layout: Keep the page's spacing, for forms and tables. Costs characters.

Input parameters:

- `layout` (boolean)
- `output` (string)
- `pages`
- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_check_access` (~230 tokens)

Check a PDF's encryption and what it permits: printing, copying, editing.

Answers "is this locked, and what am I allowed to do with it?".

\`encrypted` and `needs_password` are separate answers and the difference
matters: most encrypted files have no user password, so they open silently and
only carry restrictions. `permissions` gives a boolean per action,
\`restrictions` lists what is denied, and an unencrypted file permits
everything — a PDF has nowhere to keep restrictions but its encryption
dictionary.

Treat restrictions as what the file asks of viewers, not as enforcement: once a
document is open nothing stops the bits being ignored, and a file that denies
copying still yields its text to pdf_extract_text. Report them as the author's
intent, never as an action being impossible.

Worth reaching for when another tool reports a file as encrypted; this one
still answers, since the encryption dictionary is readable when the pages are
not.

Args:
    ref: PDF file path, or a workspace artifact id.

Input parameters:

- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_page_layout` (~275 tokens)

Measure a PDF's page sizes, orientation and rotation.

Answers "what size is this, is it all the same, and why does one page come out
sideways?". Reads page geometry only, so it stays cheap on long documents.

\`sizes` groups the pages by shape, most pages first, each carrying the page
numbers it covers as a range like "1-16,18", so a 300 page document answers in
one entry instead of 300 rows.
Sizes are the page as a reader sees it: CropBox clipped to MediaBox with
\`/Rotate` applied, so a landscape box rotated 90 degrees reports as portrait.
Pages within 3pt of a known paper are grouped and named together, since real A4
varies by a millimetre.

Pass `pages` for per page rows carrying the raw boxes: "1-20", "3", "1,5,9-12"
or "all", capped at 100 rows.

It does not look at page content; for whether the pages hold readable text use
pdf_check_text.

Args:
    ref: PDF file path, or a workspace artifact id.
    pages: Optional page range for per page detail. Omit for groups only.

Input parameters:

- `pages`
- `ref` (string, required)

Output parameters:

- `result` (object)

### `pdf_render_pages` (~299 tokens)

Render PDF pages to images, so a page can be looked at rather than read.

Use it to see what a page looks like: checking a change landed (did a redaction
remove content, did a split cut where intended), previewing, and pages where
appearance is the content — handwriting, signatures, charts, checkbox state.

For *reading* a scan prefer pdf_ocr, whose text layer is searchable and needs no
vision model; render when OCR is unavailable or would mangle what matters.

Every page is saved as a PNG artifact and its id returned. With `view`, the
default, the first few images also come back to be looked at, since images are
expensive in context. Limits are explicit: 20 pages per call, and resolution is
reduced for a page that would be enormous — both reported, never silent.

Args:
    ref: PDF file path, or a workspace artifact id.
    pages: Which pages: "1-20", "3", "1,5,9-12" or "all". Defaults to all, up
        to the per-call limit.
    dpi: Resolution, 36 to 600. 150 suits reading and previewing.
    view: Return the images to look at, not just artifact ids.

Input parameters:

- `dpi` (integer)
- `pages`
- `ref` (string, required)
- `view` (boolean)

### `pdf_ocr` (~329 tokens)

Read a scanned PDF with OCR, and optionally add a real text layer to it.

The way to read a page with no text: a scan, or an export that lost its text. Prefer it to pdf_render_pages for reading; run pdf_check_text when unsure.
Tesseract is a system install, and a missing binary or language errors with how
to install it.

OCR can be confidently wrong, so pages report `mean_confidence` and
\`low_confidence_words`: say when confidence is low rather than presenting text as
certain, and look at a bad page with pdf_render_pages.

Text pages are skipped unless `force`. A long document may stop early; when
\`truncated`, do exactly what the summary says, artifact and range included.

Args:
    ref: PDF file path, or a workspace artifact id.
    pages: Which pages: "1-10", "3", "1,5,9-12" or "all". Defaults to all.
    lang: Tesseract language code, or several as "eng+deu".
    dpi: Resolution, 72 to 600. 200 suits printed text; higher is slower, not
        better.
    output: "text", "pdf" for a searchable copy as an artifact, or "both".
    force: OCR pages that already have text instead of skipping them.

Input parameters:

- `dpi` (integer)
- `force` (boolean)
- `lang` (string)
- `output` (string)
- `pages`
- `ref` (string, required)

Output parameters:

- `result` (object)

### `create_test_pdf_file` (~119 tokens)

Create a test PDF, handy for trying the other tools without hunting for one.

The pages are blank, so this is for exercising tools rather than for anything
that needs real content.

Args:
    output_path: Optional path to also write the PDF to. Omit to keep it as a
        temporary artifact.
    num_pages: Number of blank pages to create (default: 3)
    title: Optional title for the PDF metadata

Input parameters:

- `num_pages` (integer)
- `output_path`
- `title`

Output parameters:

- `result` (object)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp#diagnostics

## Score history

- 2026-09-20: 67
- 2026-09-19: 66
- 2026-09-18: 66
- 2026-09-17: 65
- 2026-09-16: 65
- 2026-09-15: 64
- 2026-09-14: 64
- 2026-09-13: 48
- 2026-09-12: 47

## Common questions

### What is the io.github.benbergner/benspdf MCP server?

io.github.benbergner/benspdf is an MCP server listed in the public MCP registry as io.github.benbergner/benspdf. Read PDFs locally: text, pages, metadata, scan detection, layout, permissions, render, OCR. This page covers its PyPI package (benspdf-mcp).

### Is the io.github.benbergner/benspdf MCP server safe to use?

io.github.benbergner/benspdf scores 67 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.benbergner/benspdf MCP server expose?

io.github.benbergner/benspdf exposes 12 tools: export, list_artifacts, discard, pdf_page_count, pdf_metadata, and 7 more. Their descriptions and schemas cost roughly 2,471 tokens of context every time the server is loaded.

### Is the io.github.benbergner/benspdf MCP server still maintained?

io.github.benbergner/benspdf is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- PyPI project: https://pypi.org/project/benspdf-mcp/
- Socket report: https://socket.dev/pypi/package/benspdf-mcp
- Repository: https://github.com/benbergner/BensPDF
- Changelog RSS feed: https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp.json
- HTML version of this page: https://verifymcp.io/servers/benbergner-benspdf/benspdf-mcp
