关于 PDF Triage
PDF Triage 是供 AI 工具读取本地 PDF 的 MCP 服务。它先分类再提取,标记不可靠文本、限制输出长度,并将文件访问限制在指定目录内。
主要功能
- 01提取前分类 PDF
- 02标记可疑或不可靠文本
- 03提取 Markdown 和表格
- 04搜索 PDF 文本
- 05限制输出并约束文件路径
适用场景
- 01判断 PDF 是否含可提取文本
- 02在本地 PDF 中查找词语
- 03提取限长文本或表格
- 04避免依赖乱码 PDF 文本
MCP 相关
向 MCP 客户端提供四种 `pdf_*` 工具:分类、搜索、文本提取和表格提取。服务仅读取配置的 `--root` 目录内的路径。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y pdf-triage-mcpPDF_TRIAGE_LOG_LEVELMinimum severity written to stderr. Defaults to info.PDF_TRIAGE_MAX_CHARSDefault truncation ceiling for tool responses, in characters. Guards the caller's context window. Defaults to 40000.PDF_TRIAGE_MAX_FILE_BYTESLargest PDF the server will read, in bytes. The parser buffers whole files rather than streaming. Defaults to 104857600 (100 MB).本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
4收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| path | string | 是 | 允许的根目录下的 .pdf 文件绝对路径或相对路径 |
详细介绍
pdf-triage-mcp
一个 MCP 服务,让任何 AI 工具都能读取本地 PDF —— 无需上传,无需支付 OCR 费用,也不会悄悄返回垃圾内容。
基于 @firecrawl/pdf-inspector 构建(Rust,不含 ML 模型,无外部服务)。
┌─ 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
目录
为何创建此项目
大多数 PDF 工具都有相同的失效模式:无论提取是否成功,它们都会返回看似可信的文本。 CID 字体损坏、替换密码编码、没有文本层的扫描页面——你会得到看起来似乎合理的输出,至于问题是否会在后续环节被发现,就不得而知了。
pdf-inspector 非常擅长识别自身何时失败。遇到未映射的 CID 时,它会输出 U+FFFD,而不是猜测;它会检测自身输出中的替换密码;当提取的文本中英数字字符低于 50% 时,还会将文档重新归类为扫描件。但它只会在结果对象中报告这些发现,而大多数封装程序会将其丢弃。
本服务会据此采取行动。 每个响应都会在内容上方附带可信度信号,让模型优先读取这些信息:
> [!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
...
由此遵循三条设计原则:
- 先分类,再提取。
pdf_classify耗时约 20ms,可告知是否值得尝试提取。 - 限制每个输出的大小。 一份 300 页的 PDF 很容易达到 50 万个 token。所有输出默认都会截断,并告知如何翻页查看。
- 限制每个路径的访问范围。 刚读取过不可信文档的模型,不应被诱导去读取
~/.ssh/id_rsa。此限制由代码强制执行,而不是交给模型自行判断。
安装
无需安装。 以下所有配置都会直接从 npm 运行已发布的软件包:
npx -y pdf-triage-mcp --root /path/to/your/documents
MCP 客户端会为你运行这些命令——你只需粘贴配置即可。先确认其能正常运行:
npx -y pdf-triage-mcp --version
需要 Node 20+。 可通过 npm 获取 pdf-triage-mcp,也可在 MCP Registry 中找到,名称为 io.github.vishalmeena2211/pdf-triage-mcp。
改用源码(用于开发)
git clone https://github.com/vishalmeena2211/pdf-triage-mcp.git
cd pdf-triage-mcp
npm install
npm run build
node dist/index.js --root ~/Documents
然后,在下方任一配置中,用 "command": "node", "args": ["/absolute/path/to/dist/index.js", ...] 替换 npx 调用。
连接到你的 AI 工具
除一项值外,以下所有配置均可直接使用:
/Users/me/Documents— 替换为服务允许读取的目录。这是唯一必须修改的内容。
请使用绝对路径;大多数客户端不会展开 ~。如需指定多个目录,请重复使用 --root。
PATH 注意事项,适用于下方所有 GUI 客户端。 桌面应用会以精简环境启动服务,因此即使裸用
npx在终端中正常运行,也经常无法解析。如果服务无法启动,请替换为绝对路径——运行which npx查找(Apple Silicon 通常为/opt/homebrew/bin/npx,Intel macOS 通常为/usr/local/bin/npx)。
为什么要用
-y? 它会跳过 npx 的安装确认提示。若不使用它,首次运行时可能会等待输入而卡住,因为 MCP 客户端无法提供输入——服务看似启动了,之后却会悄无声息地超时。
1. Claude Desktop
配置文件
| 操作系统 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
验证: 完全退出并重新启动 Claude Desktop(不要只关闭窗口)。聊天输入框旁会出现一个工具图标 — 点击它并确认列表中有四个 pdf_* 工具。
日志:~/Library/Logs/Claude/mcp*.log(macOS)、%APPDATA%\Claude\logs\mcp*.log(Windows)。
2. Claude Code
命令行 — 最简单的方式。 -- 分隔符是必需的;它之后的所有内容都是服务命令。
# Just you, this project (default)
claude mcp add pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents
# Just you, every project
claude mcp add --scope user pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents
# Shared with your team, writes .mcp.json to the repo
claude mcp add --scope project pdf-triage -- npx -y pdf-triage-mcp --root /Users/me/Documents
或者直接编辑项目根目录中的 .mcp.json:
{
"mcpServers": {
"pdf-triage": {
"type": "stdio",
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
| 范围 | 存储位置 | 共享 |
|---|---|---|
local(默认) | ~/.claude.json 中的此项目下 | 否 |
user | ~/.claude.json 顶层 | 否 |
project | 仓库根目录中的 .mcp.json | 是,通过 git |
验证: claude mcp list → 查找 ✔ Connected。项目级服务首次使用时需要批准 — 在会话中运行 /mcp。
3. Cursor
配置文件: .cursor/mcp.json(项目)或 ~/.cursor/mcp.json(全局)。发生冲突时以项目配置为准。
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
验证: Cursor 会热重载 — 无需重启。打开 Cursor 设置 → 工具与 MCP,查找 pdf-triage 旁的绿色圆点。
4. Windsurf
配置文件: ~/.codeium/windsurf/mcp_config.json(macOS/Linux),%USERPROFILE%\.codeium\windsurf\mcp_config.json(Windows)。
首次启动时不会创建此文件 — 如果文件不存在,请自行创建。
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
验证: Windsurf 会监视该文件,并在保存时热重载。下一次聊天会话中,工具会显示在 Cascade 中。
5. VS Code + GitHub Copilot
键名是
servers,不是mcpServers。 从 Claude Desktop 复制配置时,最常见的错误就是这一点。
配置文件: .vscode/mcp.json(工作区),或命令面板 → MCP: Open User Configuration(全局)。
{
"servers": {
"pdf-triage": {
"type": "stdio",
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
命令行替代方式:
code --add-mcp '{"name":"pdf-triage","command":"npx","args":["-y","pdf-triage-mcp","--root","/Users/me/Documents"]}'
验证: MCP 工具只能在 Agent 模式下使用 — 在 Copilot Chat 中从 Ask/Edit 切换到 Agent,然后点击 配置工具并确认出现了 pdf_* 工具。首次添加文件后,请重启 VS Code。
6. Zed
键名是
context_servers,不是mcpServers, 而且command是嵌套对象,而非字符串。
配置文件: ~/.config/zed/settings.json(macOS/Linux),%APPDATA%\Zed\settings.json(Windows)。命令面板 → zed: open settings。
{
"context_servers": {
"pdf-triage": {
"source": "custom",
"command": {
"path": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
],
"env": {}
}
}
}
}
如果你的 Zed 版本不接受这种格式,说明它早于嵌套格式 — 请尝试将 command、args 和 env 平铺到服务对象的顶层。
验证: Agent 面板(Cmd+Shift+A)→ 齿轮图标 → MCP Servers。绿色圆点表示已连接。
7. Cline(VS Code 扩展)
配置文件 — 与 VS Code 自身的配置文件分开:
| 操作系统 | 路径 |
|---|---|
| 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 |
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
],
"disabled": false,
"autoApprove": ["pdf_classify", "pdf_search"]
}
}
}
autoApprove 会在无需确认提示的情况下运行所列的只读工具。
验证: 面板会自动刷新;服务旁边会显示绿色圆点。
8. Continue.dev
配置文件: ~/.continue/config.yaml(全局)或 .continue/config.yaml(项目)。当前使用 YAML;config.json 已弃用。
此处的
mcpServers是一个列表,不是对象;YAML 必须使用空格,绝不能使用制表符。
mcpServers:
- name: pdf-triage
command: npx
args:
- -y
- pdf-triage-mcp
- --root
- /Users/me/Documents
验证: 保存后会自动重新加载。将 Continue 切换到 Agent mode——其他模式下无法使用 MCP 工具。
9. Google Gemini CLI
命令行:
gemini mcp add pdf-triage npx -y pdf-triage-mcp --root /Users/me/Documents
# global instead of project-scoped
gemini mcp add --scope user pdf-triage npx -y pdf-triage-mcp --root /Users/me/Documents
或者编辑 ~/.gemini/settings.json(全局)/ .gemini/settings.json(项目):
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
],
"timeout": 30000,
"trust": false
}
}
}
验证: 在 gemini 会话中运行 /mcp,服务会显示为 CONNECTED,并列出其工具。也可以在 shell 中运行 gemini mcp list。
10. OpenAI Codex CLI
配置文件: ~/.codex/config.toml(全局)或 .codex/config.toml(项目)。
使用 TOML,键名为
mcp_servers——采用 snake_case,绝不能写成mcpServers。
[mcp_servers.pdf-triage]
command = "npx"
args = [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
startup_timeout_sec = 20
tool_timeout_sec = 60
验证: codex doctor --json 会验证配置语法。请注意,它只验证语法,不会确认服务是否实际启动。
已知的上游问题: 多个版本的 Codex CLI 存在一个错误:stdio 服务通过验证后仍会悄然启动失败,并在 TUI 中显示
Tools: none(#3441,#26810)。这是 Codex 运行时错误,不是配置错误。
11. JetBrains AI Assistant / Junie
AI Assistant — 通过 IDE 配置,无需编辑文件:
- Settings → Tools → AI Assistant → Model Context Protocol (MCP)
- Add → 传输方式选择 STDIO
- 粘贴:
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
- OK → Apply
Junie 使用文件配置——~/.junie/mcp/mcp.json(全局)或 .junie/mcp/mcp.json(项目),JSON 结构相同。
验证: 查看 MCP 设置面板中的 Status 列;点击该列即可列出服务的工具。
12. LM Studio
配置文件: ~/.lmstudio/mcp.json(macOS/Linux)、%USERPROFILE%\.lmstudio\mcp.json(Windows)。
通过应用操作更简单:右侧边栏 → Program 标签页 → Install → Edit mcp.json。
{
"mcpServers": {
"pdf-triage": {
"command": "npx",
"args": [
"-y", "pdf-triage-mcp",
"--root", "/Users/me/Documents"
]
}
}
}
验证: 保存后会自动重新加载;工具会显示在 Program 面板中。LM Studio 会在模型首次调用工具时显示确认对话框。
速查表
| 客户端 | 文件 | 顶层键 | 需要重启? |
|---|---|---|---|
| Claude Desktop | claude_desktop_config.json | mcpServers | 完全退出 |
| Claude Code | .mcp.json / CLI | mcpServers | 否 |
| Cursor | .cursor/mcp.json | mcpServers | 否 |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | mcpServers | 否 |
| VS Code Copilot | .vscode/mcp.json | servers | 首次需要 |
| Zed | ~/.config/zed/settings.json | context_servers | 否 |
| Cline | cline_mcp_settings.json | mcpServers | 否 |
| Continue.dev | ~/.continue/config.yaml | mcpServers(列表) | 否 |
| Gemini CLI | ~/.gemini/settings.json | mcpServers | 否 |
| Codex CLI | ~/.codex/config.toml | [mcp_servers.*] | 不适用 |
| JetBrains | IDE 设置界面 | mcpServers | 否 |
| LM Studio | ~/.lmstudio/mcp.json | mcpServers | 否 |
三种不同情况: VS Code(servers)、Zed(context_servers + 嵌套的 command)、Codex(TOML mcp_servers)。其余客户端均可原样使用 Claude Desktop 格式。
工具
| 工具 | 耗时 | 用途 |
|---|---|---|
pdf_classify | ~20ms | 类型、置信度、页数、需要 OCR 的确切页面。请先调用此工具。 |
pdf_extract | ~150ms | PDF → Markdown。默认会截断;使用 pages 分页提取。 |
pdf_search | ~150ms | 定位文本,返回标注页码的片段。了解长文档内容的最经济方式。 |
pdf_tables | ~150ms | 仅提取表格,输出为 Markdown 管道表格。 |
完整参数参考:docs/TOOLS.md。
处理陌生文档时的预期流程:
pdf_classify → is it text_based with no warnings?
├─ yes → pdf_search to locate → pdf_extract with `pages`
└─ no → stop; route to OCR
配置
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.
等效环境变量:PDF_TRIAGE_ROOTS(以平台的 PATH 分隔符分隔——macOS/Linux 上为 :,Windows 上为 ;)、PDF_TRIAGE_MAX_CHARS、PDF_TRIAGE_MAX_FILE_BYTES、PDF_TRIAGE_LOG_LEVEL。命令行标志优先于环境变量。
根目录是安全边界,而非便利选项。 仅授权所需的最小目录范围。检查前会解析符号链接,因此根目录中的链接若指向根目录之外,会被拒绝,而不会跟随。
引擎回退
上游仅为三个目标平台提供预构建的原生二进制文件:linux-x64-gnu、darwin-arm64、win32-x64-msvc。没有 musl 构建,也没有 Linux ARM64 构建(上游 #216),因此在 Alpine 容器、Graviton 实例和大多数边缘运行时中无法加载。
此服务优先使用原生引擎,无法使用时则回退到 WASM,后者可在任何地方运行。能力差异会如实呈现,绝不伪装:
| 原生 | WASM | |
|---|---|---|
| 分类 / 提取 | 支持 | 支持 |
| 逐页提取 | 支持 | 不支持 — 会抛出异常,且 pdf_search 会报告其匹配结果没有页码归属 |
pages 选择 | 支持 | 不支持 — 会被忽略,响应中也会说明 |
查看使用的是哪个引擎:pdf_classify 会报告引擎,服务启动时会在日志中记录 engine selected。
已知限制
这些限制继承自上游。信任输出前,值得先了解:
- RTL 脚本无法正确处理。 阿拉伯语和希伯来语文本会以视觉顺序返回,顺序颠倒、无法使用,却被报告为
text_based且置信度很高(#212)。此服务会检测并升级处理此问题——这是我们主动防范的唯一一种上游故障模式。 - 不恢复 xref。
pypdf和pdfium会静默修复的格式错误 PDF,在此处会抛出异常(#228)。 - 日文 CIDFontType0(CFF) 子集字体可能会解码为无关字形(#208)。
- 多栏阅读顺序在某些版面中可能按光栅顺序输出,即使检测到了分栏(#219)。
- 图像不是 PDF。 扫描版 JPEG 没有文本层;服务会拒绝非 PDF 输入,而不会假装能够处理。
开发
npm run typecheck # tsc --noEmit, maximum strictness
npm test # vitest, 108 tests
npm run test:coverage
npm run build
npm run dev # tsx, no build step
TypeScript 配置启用了所有严格性标志,包括 exactOptionalPropertyTypes 和 noUncheckedIndexedAccess。上游响应会在边界处使用 Zod 验证,而非进行类型断言——原因请参见 docs/ARCHITECTURE.md。
调试客户端连接:
node dist/index.js --root ~/Documents --log-level debug
故障排查:docs/TROUBLESHOOTING.md。
路线图
-
pdf_regions— 为混合模型流水线提供基于 bbox 范围的提取 - 提供
{page, bbox}的定位项工具,支持视觉引用体验 - 集成测试,验证原生引擎和 WASM 是否生成相同的规范化结构
- 可选的 OCR 适配器接口,端到端打通路由闭环
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。