PDF Triage

io.github.vishalmeena2211由 GitHub 账号 vishalmeena2211 发布v0.1.2更新于 Oct 24, 2026

Read local PDFs without uploading. Classifies first, flags untrustworthy text, bounds output.

已验证STDIO仅桌面文件与存储知识与记忆

概览

AI 生成的概览

让助手在不上传文件的情况下读取本地 PDF,先对文件分类并标记不可靠的文本提取结果。

可以做什么
以 stdio 方式在本地运行,提供四个只读工具:pdf_classify 报告文档类型、置信度、页数和需要 OCR 的页面;pdf_extract 将 PDF 转为 Markdown;pdf_search 返回带页码的文本片段;pdf_tables 只返回管道表格。当检测到编码问题或扫描页时,每条响应都会在正文之前给出可信度警告,输出默认截断并说明如何分页读取。
适用场景
适合助手需要读取必须留在本机的 PDF,以及希望在信任文本之前先确认提取是否真的成功。先分类的流程适用于不熟悉或很长的文档,用一次低成本检查避免把上下文浪费在扫描件或乱码文件上。
运行要求
需要 Node.js 20 或更高版本;通过 npx 以 pdf-triage-mcp 运行,或使用本地构建。必须提供至少一个 --root 目录(绝对路径,可重复)。可选环境变量 PDF_TRIAGE_LOG_LEVEL、PDF_TRIAGE_MAX_CHARS、PDF_TRIAGE_MAX_FILE_BYTES 用于调整日志与限制。无需账号或 API 密钥。
安装前请注意
--root 目录是安全边界:应只授予最小可用目录,因为服务器会读取其中的文件。它是只读的,不会上传文档,但提取出的文本会返回给调用的模型,因此不可信的 PDF 仍会进入助手上下文。已知限制包括从右到左文字排版异常、无法修复 xref,以及部分日文 CID 字体可能解码错误。

安装

在 SourceWeft 中

  1. 打开 控制台中的 PDF Triage,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

pdf-triage-mcp

[npm] [CI] [MCP Registry] [License: MIT]

An MCP server that lets any AI tool read local PDFs — without uploading them, without an OCR bill, and without silently handing back garbage.

Built on @firecrawl/pdf-inspector (Rust, no ML models, no external services).

┌─ pdf_classify ──→  text_based · 0.98 · 12 pages · 0 need OCR   ~20ms├─ pdf_search  ──→  "invoice total" found on p4, p9              ~150ms├─ pdf_extract ──→  clean Markdown, truncated to your budget     ~150ms└─ pdf_tables  ──→  just the pipe tables, no prose               ~150ms

Table of contents


Why this exists

Most PDF tooling has the same failure mode: it returns confident text regardless of whether extraction actually worked. Broken CID fonts, substitution-cipher encodings, scanned pages with no text layer — you get plausible-looking output and find out downstream, if at all.

pdf-inspector is unusually good at knowing when it failed. It emits U+FFFD rather than guessing at an unmapped CID, runs substitution-cipher detection over its own output, and reclassifies a document as scanned when extracted text drops below 50% alphanumeric. But it stops at reporting those findings on a result object — and most wrappers throw them away.

This server acts on them. Every response carries the trust signals, above the content, where the model reads them first:

markdown
> [!WARNING] ENCODING ISSUES DETECTED. The text layer decoded to suspicious> output — typically a garbled CID font or a substitution-cipher encoding> where letter frequencies match natural language but the letters themselves> are wrong. Treat all extracted text here as unreliable and prefer OCR.
---
# Quarterly Report...

Three design rules follow:

  1. Classify before extracting. pdf_classify costs ~20ms and tells you whether extraction is worth attempting at all.
  2. Bound every output. A 300-page PDF is easily 500k tokens. Everything truncates by default and tells you how to page through instead.
  3. Confine every path. A model that has just read an untrusted document must not be talkable into reading ~/.ssh/id_rsa. Enforced in code, not left to the model's judgement.

Install

Nothing to install. Every config below runs the published package straight from npm:

npx -y pdf-triage-mcp --root /path/to/your/documents

Your MCP client runs that for you — you only need to paste the config. Confirm it works first:

bash
npx -y pdf-triage-mcp --version

Requires Node 20+. Available on npm as pdf-triage-mcp and in the MCP Registry as io.github.vishalmeena2211/pdf-triage-mcp.

From source instead (for development)
bash
git clone https://github.com/vishalmeena2211/pdf-triage-mcp.gitcd pdf-triage-mcpnpm installnpm run buildnode dist/index.js --root ~/Documents

Then substitute "command": "node", "args": ["/absolute/path/to/dist/index.js", ...] for the npx invocation in any config below.


Connect it to your AI tool

Every config below is complete as written except for one value:

  • /Users/me/Documents — replace with the directory the server may read. This is the only thing you must change.

Use an absolute path; ~ is not expanded by most clients. Repeat --root for multiple directories.

PATH gotcha, applies to every GUI client below. Desktop apps launch servers with a minimal environment, so bare npx often fails to resolve even though it works in your terminal. If the server won't start, substitute the absolute path — find it with which npx (commonly /opt/homebrew/bin/npx on Apple Silicon, /usr/local/bin/npx on Intel macOS).

Why -y? It skips npx's install confirmation prompt. Without it, a first run can hang waiting for input that an MCP client cannot provide — the server appears to start and then silently times out.

1. Claude Desktop

Config file

OSPath
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json
json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}

Verify: Fully quit and relaunch Claude Desktop (not just close the window). A tools icon appears near the chat input — click it and confirm the four pdf_* tools are listed.

Logs: ~/Library/Logs/Claude/mcp*.log (macOS), %APPDATA%\Claude\logs\mcp*.log (Windows).

Docs

2. Claude Code

CLI — the easiest route. The -- separator is mandatory; everything after it is the server command.

bash
# Just you, this project (default)claude mcp add pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents
# Just you, every projectclaude mcp add --scope user pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents
# Shared with your team, writes .mcp.json to the repoclaude mcp add --scope project pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents

Or edit .mcp.json at the project root directly:

json
{  "mcpServers": {    "pdf-triage": {      "type": "stdio",      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}
ScopeStored inShared
local (default)~/.claude.json, under this projectNo
user~/.claude.json, top levelNo
project.mcp.json in repo rootYes, via git

Verify: claude mcp list → look for ✔ Connected. Project-scoped servers need approval on first use — run /mcp inside a session.

Docs

3. Cursor

Config file: .cursor/mcp.json (project) or ~/.cursor/mcp.json (global). Project wins on conflict.

json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}

Verify: Cursor hot-reloads — no restart. Open Cursor Settings → Tools & MCP and look for a green dot next to pdf-triage.

Docs

4. Windsurf

Config file: ~/.codeium/windsurf/mcp_config.json (macOS/Linux), %USERPROFILE%\.codeium\windsurf\mcp_config.json (Windows).

Not created on first launch — create it yourself if missing.

json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}

Verify: Windsurf watches the file and hot-reloads on save. Tools appear in Cascade on the next chat session.

Docs

5. VS Code + GitHub Copilot

The key is servers, not mcpServers. This is the most common mistake when copying a config from Claude Desktop.

Config file: .vscode/mcp.json (workspace), or Command Palette → MCP: Open User Configuration (global).

json
{  "servers": {    "pdf-triage": {      "type": "stdio",      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}

CLI alternative:

bash
code --add-mcp '{"name":"pdf-triage","command":"npx","args":["-y","pdf-triage-mcp","--root","/Users/me/Documents"]}'

Verify: MCP tools only work in Agent mode — switch from Ask/Edit to Agent in Copilot Chat, then click Configure Tools and confirm the pdf_* tools appear. Restart VS Code after first adding the file.

Docs

6. Zed

The key is context_servers, not mcpServers, and command is a nested object rather than a string.

Config file: ~/.config/zed/settings.json (macOS/Linux), %APPDATA%\Zed\settings.json (Windows). Command Palette → zed: open settings.

json
{  "context_servers": {    "pdf-triage": {      "source": "custom",      "command": {        "path": "npx",        "args": [          "-y", "pdf-triage-mcp",          "--root", "/Users/me/Documents"        ],        "env": {}      }    }  }}

If your Zed version rejects that, it predates the nested form — try command, args and env flat at the top level of the server object instead.

Verify: Agent Panel (Cmd+Shift+A) → gear icon → MCP Servers. Green dot means connected.

Docs

7. Cline (VS Code extension)

Config file — separate from VS Code's own:

OSPath
macOS~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
Windows%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
Linux~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ],      "disabled": false,      "autoApprove": ["pdf_classify", "pdf_search"]    }  }}

autoApprove runs the listed read-only tools without a confirmation prompt.

Easier route: Cline panel → MCP servers icon → Edit MCP Settings opens this file directly.

Verify: Panel refreshes automatically; green dot next to the server.

Docs

8. Continue.dev

Config file: ~/.continue/config.yaml (global) or .continue/config.yaml (project). YAML is current; config.json is deprecated.

mcpServers here is a list, not an object — and YAML needs spaces, never tabs.

yaml
mcpServers:  - name: pdf-triage    command: npx    args:      - -y      - pdf-triage-mcp      - --root      - /Users/me/Documents

Verify: Reloads automatically on save. Switch Continue to Agent mode — MCP tools are unavailable in other modes.

Docs

9. Google Gemini CLI

CLI:

bash
gemini mcp add pdf-triage npx -y pdf-triage-mcp --root /Users/me/Documents
# global instead of project-scopedgemini mcp add --scope user pdf-triage npx -y pdf-triage-mcp --root /Users/me/Documents

Or edit ~/.gemini/settings.json (global) / .gemini/settings.json (project):

json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ],      "timeout": 30000,      "trust": false    }  }}

Verify: Run /mcp inside a gemini session — servers show CONNECTED with their tool list. Or gemini mcp list from the shell.

Docs

10. OpenAI Codex CLI

Config file: ~/.codex/config.toml (global) or .codex/config.toml (project).

TOML, and the key is mcp_servers — snake_case, never mcpServers.

toml
[mcp_servers.pdf-triage]command = "npx"args = [  "-y", "pdf-triage-mcp",  "--root", "/Users/me/Documents"]startup_timeout_sec = 20tool_timeout_sec = 60

Verify: codex doctor --json validates the config syntax. Note that it validates syntax only — it does not confirm the server actually spawned.

Known upstream issue: several Codex CLI versions have a bug where stdio servers validate cleanly but silently fail to start, showing Tools: none in the TUI (#3441, #26810). That is a Codex runtime bug, not a config error.

Docs

11. JetBrains AI Assistant / Junie

AI Assistant — configured through the IDE, no file to edit:

  1. Settings → Tools → AI Assistant → Model Context Protocol (MCP)
  2. Add → transport STDIO
  3. Paste:
json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}
  1. OK → Apply

Junie uses a file instead — ~/.junie/mcp/mcp.json (global) or .junie/mcp/mcp.json (project), same JSON shape.

Verify: Check the Status column in the MCP settings panel; click it to list the server's tools.

Docs

12. LM Studio

Config file: ~/.lmstudio/mcp.json (macOS/Linux), %USERPROFILE%\.lmstudio\mcp.json (Windows).

Easier via the app: right sidebar → Program tab → Install → Edit mcp.json.

json
{  "mcpServers": {    "pdf-triage": {      "command": "npx",      "args": [        "-y", "pdf-triage-mcp",        "--root", "/Users/me/Documents"      ]    }  }}

Verify: Auto-reloads on save; tools appear in the Program panel. LM Studio shows a confirmation dialog the first time a model calls a tool.

Docs

Cheat sheet

ClientFileTop-level keyRestart?
Claude Desktopclaude_desktop_config.jsonmcpServersFull quit
Claude Code.mcp.json / CLImcpServersNo
Cursor.cursor/mcp.jsonmcpServersNo
Windsurf~/.codeium/windsurf/mcp_config.jsonmcpServersNo
VS Code Copilot.vscode/mcp.jsonserversFirst time
Zed~/.config/zed/settings.jsoncontext_serversNo
Clinecline_mcp_settings.jsonmcpServersNo
Continue.dev~/.continue/config.yamlmcpServers (list)No
Gemini CLI~/.gemini/settings.jsonmcpServersNo
Codex CLI~/.codex/config.toml[mcp_servers.*]N/A
JetBrainsIDE settings UImcpServersNo
LM Studio~/.lmstudio/mcp.jsonmcpServersNo

The three that differ: VS Code (servers), Zed (context_servers + nested command), Codex (TOML mcp_servers). Everything else takes the Claude Desktop format verbatim.


Tools

ToolCostPurpose
pdf_classify~20msType, confidence, page count, exact pages needing OCR. Call this first.
pdf_extract~150msPDF → Markdown. Truncates by default; slice with pages.
pdf_search~150msLocate text, return page-attributed snippets. Cheapest way into a long document.
pdf_tables~150msTables only, as Markdown pipe tables.

Full parameter reference: docs/TOOLS.md.

The intended flow on an unfamiliar document:

pdf_classify → is it text_based with no warnings?  ├─ yes → pdf_search to locate → pdf_extract with `pages`  └─ no  → stop; route to OCR

Configuration

pdf-triage-mcp [options]
  -r, --root <dir>          Directory the server may read. Repeatable. Default: cwd.      --max-chars <n>       Default truncation ceiling. Default: 40000. Max: 200000.      --max-file-bytes <n>  Largest PDF to read. Default: 104857600 (100 MB).      --log-level <level>   debug | info | warn | error | silent. Default: info.  -h, --help                Show usage.  -v, --version             Print version.

Environment equivalents: PDF_TRIAGE_ROOTS (separated by the platform PATH delimiter — : on macOS/Linux, ; on Windows), PDF_TRIAGE_MAX_CHARS, PDF_TRIAGE_MAX_FILE_BYTES, PDF_TRIAGE_LOG_LEVEL. Flags win over environment.

Roots are a security boundary, not a convenience. Grant the narrowest directory that works. Paths are resolved through symlinks before checking, so a link inside a root pointing outside it is rejected rather than followed.


Engine fallback

Upstream ships prebuilt native binaries for exactly three targets: linux-x64-gnu, darwin-arm64, win32-x64-msvc. No musl build, no Linux ARM64 build (upstream #216) — so it fails to load on Alpine containers, Graviton instances, and most edge runtimes.

This server prefers native and falls back to WASM, which runs anywhere. Capability differences are surfaced, never faked:

NativeWASM
Classify / extractYesYes
Per-page extractionYesNo — throws, and pdf_search reports its matches are unattributed
pages selectionYesNo — ignored, and the response says so

Check which engine you got: pdf_classify reports it, and the server logs engine selected at startup.


Known limitations

Inherited from upstream. Worth reading before you trust output:

  • RTL scripts are broken. Arabic and Hebrew return in visual order, reversed and unusable, while being reported as text_based with high confidence (#212). This server detects and escalates it — the one upstream failure mode we actively guard.
  • No xref recovery. Malformed PDFs that pypdf and pdfium silently repair will throw (#228).
  • Japanese CIDFontType0 (CFF) subset fonts can decode to unrelated glyphs (#208).
  • Multi-column reading order may emit in raster order on some layouts despite columns being detected (#219).
  • Images are not PDFs. A scanned JPEG has no text layer; the server rejects non-PDF input rather than pretending otherwise.

Development

bash
npm run typecheck    # tsc --noEmit, maximum strictnessnpm test             # vitest, 108 testsnpm run test:coveragenpm run buildnpm run dev          # tsx, no build step

The TypeScript config runs every strictness flag including exactOptionalPropertyTypes and noUncheckedIndexedAccess. Upstream responses are validated with Zod at the boundary rather than cast — see docs/ARCHITECTURE.md for why.

Debug a client connection:

bash
node dist/index.js --root ~/Documents --log-level debug

Troubleshooting: docs/TROUBLESHOOTING.md.


Roadmap

  • pdf_regions — bbox-scoped extraction for hybrid model pipelines
  • Positioned-item tool exposing {page, bbox} for visual citation UX
  • Integration tests asserting native and WASM produce identical normalized shapes
  • Optional OCR adapter interface, closing the routing loop end to end

License

MIT

来源:README.md,提交 d653691

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.1.2最新Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分