# Reported issues for pdf-mcp

Pod holds 12 of 12 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to [pdf-mcp](/mcp/pdf-mcp).

## Most discussed

### add support for reading simple charts with PlotDigitizer

https://apps.automeris.io/wpd4/ something like this automatically?

if this is possible, I will package it into nixpkags (making it available for all NixOS).

[Read the thread](https://github.com/jztan/pdf-mcp/issues/23) · 2026-07-13 · closed · external user · 10 comments

### ocr_lang is not part of the page-text cache key: first OCR language wins permanently

## Summary

`ocr_lang` is not part of the page-text cache key, so the **first language used to OCR a page wins permanently**. Any later `pdf_read_pages(..., ocr=True, ocr_lang=<other>)` on that page silently returns the *previous* language's text — instantly, labeled `source: "ocr"`, with no error or warning.

This is easy to misdiagnose as "the Tesseract language pack isn't installed" or "language X doesn't work", because the failure is indistinguishable from a bad OCR result.

## Reproduction

[Read the thread](https://github.com/jztan/pdf-mcp/issues/25) · 2026-08-03 · closed · external user · 6 comments

### ocr_lang cache key is not normalized: case and spelling variants create distinct rows

Follow-up to #25, from @deepdmk's verification of the 2.1.0 fix ([comment](https://github.com/jztan/pdf-mcp/issues/25#issuecomment-5235175023)).

`ocr_lang` goes verbatim from the tool argument into both the `page_text.ocr_lang` column and Tesseract's `-l` flag. Nothing lowercases, strips, or otherwise normalizes it in `server.py` or `extractor.py`, and `_is_ocr_cache_hit` compares it with exact string equality. Different spellings of one language set are therefore different cache keys.

Measure

[Read the thread](https://github.com/jztan/pdf-mcp/issues/27) · 2026-08-10 · closed · 3 comments

### Keyword search ranking depends on unrelated cached PDFs (FTS5 bm25 uses table-wide IDF)

## Summary

Keyword-mode `pdf_search` ranks the pages of a single PDF, but the BM25 score
is computed over the **entire shared FTS table**. So a PDF's page ranking
depends on every *other* document the user happens to have cached — the same
query on the same PDF can return a different page order depending on unrelated
cached PDFs. Intra-document ranking should arguably be stable regardless of
what else is cached.

## Where

`PDFCache.search_fts` (`src/pdf_mcp/cache.py`):

```sql
SELECT ..., -bm2

[Read the thread](https://github.com/jztan/pdf-mcp/issues/17) · 2026-06-24 · closed · 2 comments

### URL download fails TLS verification on relative HTTP redirects (IP-pinning drops hostname)

## Summary

`URLFetcher.fetch()` fails with a TLS certificate error when a download
follows a **relative** HTTP redirect. The IP-pinning hardening rewrites each
request to the resolved IP literal, but on a relative `Location` redirect the
hostname is lost, so the next hop verifies the server certificate against the
IP address instead of the hostname.

This breaks cold-cache downloads of any URL that issues a relative redirect
(arXiv does this today). It is masked everywhere by the download cache

[Read the thread](https://github.com/jztan/pdf-mcp/issues/16) · 2026-06-24 · closed · 1 comment

### Use per-user cache directory for URL downloads

## Summary

`URLFetcher` defaults downloaded PDF cache files to `tempfile.gettempdir() / "pdf-mcp" / "downloads"`, which is usually `/tmp/pdf-mcp/downloads` on Linux/macOS. Because the directory is created with private permissions (`chmod 0o700`), the first local user to start pdf-mcp can make the shared `/tmp/pdf-mcp` path inaccessible to other local users.

This can cause startup or runtime failures on shared machines, CI runners, or multi-user development boxes.

## Current Behavior

In `src/

[Read the thread](https://github.com/jztan/pdf-mcp/issues/15) · 2026-06-24 · closed · external user · 1 comment

### Suppress PyMuPDF swigvarlink DeprecationWarning

## Problem

PyMuPDF's SWIG bindings emit a `DeprecationWarning` on import and cleanup:

```
<sys>:0: DeprecationWarning: builtin type swigvarlink has no __module__ attribute
```

This is a known upstream PyMuPDF/SWIG issue. The warning leaks through to any tool that uses `pdf-mcp` as an MCP server, creating noisy output for end users.

## Suggested Fix

Add a targeted warning filter before `pymupdf` is imported:

```python
import warnings
warnings.filterwarnings("ignore", category=DeprecationWar

[Read the thread](https://github.com/jztan/pdf-mcp/issues/6) · 2026-03-14 · closed · 1 comment

### PDF validation can be bypassed when URL ends with .pdf

## Description

In `src/pdf_mcp/url_fetcher.py`, the PDF validation logic skips the magic-bytes (`%PDF`) check if the original URL ends with `.pdf`, even if the response `Content-Type` is non-PDF (e.g. `text/html`). This means a `.pdf` URL returning HTML content would be cached and processed as if it were a valid PDF.

## Suggested Fix

- Base the extension check on the final URL after redirects (`current_url`/`response.url`) rather than the original URL
- Always enforce the `%PDF` magic-bytes c

[Read the thread](https://github.com/jztan/pdf-mcp/issues/3) · 2026-02-24 · closed · 1 comment

## Most recent

### pdf_extract_chart splits dashed curves when dash lengths are below 1

## Summary

`pdf_extract_chart` can split a single dashed curve into several phantom
series when the chart uses dash lengths below 1.

## Cause

`_dash_key()` in `src/pdf_mcp/chart_extractor.py` parses the dash pattern with:

```python
re.findall(r"-?\d+(?:\.\d+)?", str(raw))
```

That requires a digit before the decimal point. PyMuPDF writes dash lengths
below 1 without a leading zero, so real output looks like:

```
[ 1.0834783 .4685312 ] 0
```

The pattern cannot match `.4685312` as a whole, 

[Read the thread](https://github.com/jztan/pdf-mcp/issues/29) · 2026-08-22 · closed · 0 comments

### Hung OCR worker still hangs: in-parent timeout fallback has no timeout

## Summary

`run_pages()` in `parallel.py` (reworked in #18) adds `as_completed(timeout=)`
to stop a hung worker from blocking forever. But the timeout only bounds the
*wait on the pool* — the fallback then re-runs each incomplete page **in the
parent process with no timeout**, so a page that genuinely hangs inside
Tesseract's native binding still produces an unbounded hang.

This is **not a regression** — pre-#18 `pool.map()` also hung forever on a stuck
worker. It's that the #18 fix doesn't fu

[Read the thread](https://github.com/jztan/pdf-mcp/issues/20) · 2026-07-06 · closed · 0 comments

### URL fetcher rejects valid password-protected PDFs as "truncated"

## Summary

`URLFetcher._validate_pdf_content()` (added in #18) false-rejects valid
password-protected PDFs, failing with a misleading "zero pages — likely a
truncated file" error. Pre-#18 these PDFs were accepted (magic-byte check
only), so this is a regression introduced by the PDF-validation change.

Impact is narrow — only URL-fetched, encrypted PDFs — which is why it was
split out of #18 rather than blocking it.

## Root cause

`_validate_pdf_content()` checks page count before the encrypti

[Read the thread](https://github.com/jztan/pdf-mcp/issues/19) · 2026-07-06 · closed · 0 comments

### Your MCP server is graded 🟢 SAFE on Agent Skills Hub

Hi! I run [Agent Skills Hub](https://agentskillshub.top/), an open directory that security-grades & quality-scores MCP servers and agent skills. {repo} came through 🟢 SAFE — nice work. If useful, you can show the grade in your README:

[![Security-graded by Agent Skills Hub](https://agentskillshub.top/badge/jztan/pdf-mcp.svg)](https://agentskillshub.top/skill/jztan/pdf-mcp/)

It renders a 🟢 SAFE badge linking to your skill's page (grade + quality breakdown). No strings — just a trust signal fo

[Read the thread](https://github.com/jztan/pdf-mcp/issues/14) · 2026-06-23 · closed · external user · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/jztan/pdf-mcp/issues).
