使用说明
📄 PDF MCP服务器
高性能 主控程序 用于PDF处理的服务器,内置于Rust中。
为您的AI代理提供强大的PDF功能——提取文本、搜索、拆分、合并、加密等。所有依赖项都是Apache 2.0许可的,使您的项目保持干净和宽容。
✨ 特性
| 类别 | 工具 |
|---|---|
| 📖 阅读 | extract_text · extract_metadata · extract_outline · extract_annotations · extract_links · extract_form_fields |
| 🔍 搜索与发现 | search · list_pdfs · get_page_info · summarize_structure |
| 🖼️ 媒体 | 图像提取(通过 extract_text) · convert_page_to_image |
| ✂️ 操纵 | split_pdf · merge_pdfs · compress_pdf · fill_form |
| 🔒 安全 | protect_pdf · unprotect_pdf ·密码保护PDF支持·路径沙盒·SSRF保护 |
| 📦 资源 | 将PDF作为MCP资源公开,以便客户端直接访问 |
| ⚡ 演出 | 批处理·LRU缓存(带字节预算)·通过缓存键进行操作链接 |
🚀 安装
npm(推荐)
npm install -g @paradyno/pdf-mcp-server
预构建二进制文件
下载自 GitHub发布:
| 平台 | x86_64 | ARM64 |
|---|---|---|
| 🐧 Linux | pdf-mcp-server-linux-x64 |
pdf-mcp-server-linux-arm64 |
| 🍎 macOS | pdf-mcp-server-darwin-x64 |
pdf-mcp-server-darwin-arm64 |
| 🪟 窗户 | pdf-mcp-server-windows-x64.exe |
— |
来源
cargo install --git https://github.com/paradyno/pdf-mcp-server
⚙️ 配置
克劳德桌面版
添加到您的 claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - 窗户:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"pdf": {
"command": "npx",
"args": ["@paradyno/pdf-mcp-server"]
}
}
}
克劳德代码
claude mcp add pdf -- npx @paradyno/pdf-mcp-server
VS Code
{
"mcp.servers": {
"pdf": {
"command": "npx",
"args": ["@paradyno/pdf-mcp-server"]
}
}
}
🛠️ 工具
源类型
所有工具都接受多种格式的PDF源:
{ "path": "/documents/file.pdf" }
{ "base64": "JVBERi0xLjQK..." }
{ "url": "https://example.com/document.pdf" }
{ "cache_key": "abc123" }
📖 extract_text
使用LLM优化格式提取文本内容(段落检测、多列重新排序、水印删除)。
Example & Parameters
{
"sources": [{ "path": "/documents/report.pdf" }],
"pages": "1-10",
"include_metadata": true
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
pages |
string | 否 | 全部 | 页面选择(例如。, "1-5,10,15-20") |
include_metadata |
boolean | 否 | true | 包含PDF元数据 |
include_images |
boolean | 否 | 假 | 包括提取的图像(base64 PNG) |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
📖 extract_outline
提取PDF书签/目录。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/book.pdf" }]
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
答复:
{
"results": [{
"source": "/documents/book.pdf",
"outline": [
{
"title": "Chapter 1: Introduction",
"page": 1,
"children": [
{ "title": "1.1 Background", "page": 3, "children": [] }
]
}
]
}]
}
📖 extract_metadata
提取PDF元数据(作者、标题、日期等),而不加载完整内容。
Example & Parameters
{
"sources": [{ "path": "/documents/report.pdf" }]
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
📖 extract_annotations
提取突出显示、注释、下划线和其他注释。
Example & Parameters
{
"sources": [{ "path": "/documents/report.pdf" }],
"annotation_types": ["highlight", "text"],
"pages": "1-5"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
annotation_types |
array | 否 | 全部 | 按类型筛选(突出显示、下划线、文本等) |
pages |
string | 否 | 全部 | 页面选择 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
📖 extract_links
提取超链接和内部页面导航链接。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/paper.pdf" }],
"pages": "1-10"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
pages |
string | 否 | 全部 | 页面选择 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
答复:
{
"results": [{
"source": "/documents/paper.pdf",
"links": [
{ "page": 1, "url": "https://example.com", "text": "Click here" },
{ "page": 3, "dest_page": 10, "text": "See Chapter 5" }
],
"total_count": 2
}]
}
📖 extract_form_fields
从PDF表单中读取表单字段名称、类型、当前值和属性。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/form.pdf" }],
"pages": "1"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
pages |
string | 否 | 全部 | 页面选择 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
答复:
{
"results": [{
"source": "/documents/form.pdf",
"fields": [
{
"page": 1,
"name": "full_name",
"field_type": "text",
"value": "John Doe",
"is_read_only": false,
"is_required": true,
"properties": { "is_multiline": false, "is_password": false }
},
{
"page": 1,
"name": "agree_terms",
"field_type": "checkbox",
"is_checked": true,
"is_read_only": false,
"is_required": false,
"properties": {}
}
],
"total_fields": 2
}]
}
🖼️ convert_page_to_image
将PDF页面渲染为PNG图像(base64)。使Vision LLM能够理解视觉布局、图表和示意图。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/chart.pdf" }],
"pages": "1-3",
"width": 1200
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
pages |
string | 否 | 全部 | 页面选择 |
width |
integer | 否 | 1200 | 目标宽度(像素) |
height |
integer | 否 | -- | 目标高度(像素) |
scale |
float | 否 | -- | 比例因子(覆盖宽度/高度) |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
答复:
{
"results": [{
"source": "/documents/chart.pdf",
"pages": [
{
"page": 1,
"width": 1200,
"height": 1553,
"data_base64": "iVBORw0KGgo...",
"mime_type": "image/png"
}
]
}]
}
🔍 search
在PDF中使用周围上下文进行全文搜索。
Example & Parameters
{
"sources": [{ "path": "/documents/manual.pdf" }],
"query": "error handling",
"context_chars": 100
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
query |
string | 是 | -- | 搜索查询 |
case_sensitive |
boolean | 否 | false | 区分大小写的搜索 |
max_results |
integer | 否 | 100 | 要返回的最大结果 |
context_chars |
integer | 否 | 50 | 匹配周围的上下文字符 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
🔍 get_page_info
获取页面尺寸、单词/字符计数、标记估计值和文件大小。可用于规划LLM上下文使用。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/report.pdf" }]
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
skip_file_sizes |
boolean | 否 | false | 跳过文件大小计算(更快) |
答复:
{
"results": [{
"source": "/documents/report.pdf",
"pages": [{
"page": 1,
"width": 612.0, "height": 792.0,
"rotation": 0, "orientation": "portrait",
"char_count": 2500, "word_count": 450,
"estimated_token_count": 625,
"file_size": 102400
}],
"total_pages": 10,
"total_chars": 25000,
"total_words": 4500,
"total_estimated_token_count": 6250
}]
}
注: 令牌计数是依赖于模型的近似值(拉丁语为~4个字符/令牌,CJK为~2个字符/字符)。仅用作粗略的指导。
🔍 summarize_structure
一个调用PDF结构的全面概述。帮助LLM决定如何处理文档。
Example, Parameters & Response
{
"sources": [{ "path": "/documents/report.pdf" }]
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | PDF源 |
password |
string | 否 | -- | PDF密码(如果已加密) |
cache |
boolean | 否 | false | 启用缓存 |
答复:
{
"results": [{
"source": "/documents/report.pdf",
"page_count": 25,
"file_size": 1048576,
"metadata": { "title": "Annual Report", "author": "Acme Corp" },
"has_outline": true,
"outline_items": 12,
"total_chars": 50000,
"total_words": 9000,
"total_estimated_tokens": 12500,
"pages": [
{ "page": 1, "width": 612.0, "height": 792.0, "char_count": 2000, "word_count": 360, "has_images": true, "has_links": false, "has_annotations": false }
],
"total_images": 5,
"total_links": 3,
"total_annotations": 2,
"has_form": false,
"form_field_count": 0,
"form_field_types": {},
"is_encrypted": false
}]
}
🔍 list_pdfs
使用可选过滤功能在目录中查找PDF文件。
Example & Parameters
{
"directory": "/documents",
"recursive": true,
"pattern": "invoice*.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
directory |
string | 是 | -- | 要搜索的目录 |
recursive |
boolean | 否 | false | 搜索子目录 |
pattern |
string | 否 | -- | 文件名模式(例如。, "report*.pdf") |
✂️ split_pdf
从PDF中提取特定页面以创建新的PDF。
Example, Parameters & Page Range Syntax
{
"source": { "path": "/documents/book.pdf" },
"pages": "1-10,15,20-z",
"output_path": "/output/excerpt.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
source |
对象 | 是 | -- | PDF源 |
pages |
string | Yes | -- | 页面范围(见下面的语法) |
output_path |
string | 否 | -- | 将输出保存到文件 |
password |
string | 否 | -- | PDF密码(如果已加密) |
页面范围语法:
| 语法 | 描述 |
|---|---|
1-5 |
第1至5页 |
1,3,5 |
具体页面 |
z |
最后一页 |
r1 |
最后一页(反面) |
5-z |
第5页结束 |
z-1 |
所有页面均已反转 |
1-z:odd |
只有奇数页 |
1-z:even |
甚至只有页面 |
1-10,x5 |
第1至10页,第5页除外 |
✂️ merge_pdfs
将多个PDF合并到一个文件中。
Example & Parameters
{
"sources": [
{ "path": "/documents/chapter1.pdf" },
{ "path": "/documents/chapter2.pdf" }
],
"output_path": "/output/complete-book.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sources |
array | 是 | -- | 要合并的PDF源(按顺序) |
output_path |
string | 否 | -- | 将输出保存到文件 |
✂️ compress_pdf
使用流优化、对象重复数据删除和压缩来减小PDF文件大小。
Example, Parameters & Response
{
"source": { "path": "/documents/large-report.pdf" },
"compression_level": 9,
"output_path": "/output/compressed.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
source |
对象 | 是 | -- | PDF源 |
object_streams |
string | 否 | "generate" |
"generate" (最好)· "preserve" · "disable" |
compression_level |
integer | 否 | 9 | 1–9(越高=压缩越好) |
output_path |
string | 否 | -- | 将输出保存到文件 |
password |
string | 否 | -- | PDF密码(如果已加密) |
答复:
{
"results": [{
"source": "/documents/large-report.pdf",
"original_size": 5242880,
"compressed_size": 2097152,
"compression_ratio": 0.4,
"bytes_saved": 3145728
}]
}
✂️ fill_form
将值写入现有的PDF表单字段并生成新的PDF。
Example, Parameters & Limitations
{
"source": { "path": "/documents/form.pdf" },
"field_values": [
{ "name": "full_name", "value": "Jane Smith" },
{ "name": "agree_terms", "checked": true }
],
"output_path": "/output/filled-form.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
source |
对象 | 是 | -- | PDF源 |
field_values |
array | 是 | -- | 要填写的字段(见下文) |
output_path |
string | 否 | -- | 将输出保存到文件 |
password |
string | 否 | -- | PDF密码(如果已加密) |
字段值格式:
| 字段 | 类型 | 描述 |
|---|---|---|
name |
string | 字段名(使用 extract_form_fields 查找名称) |
value |
string | 文本值(用于文本字段) |
checked |
boolean | 选中状态(用于复选框/单选字段) |
支持的字段类型: 文本字段、复选框、单选按钮。组合框/列表框选择是只读的。
🔒 protect_pdf
使用256位AES加密添加密码保护。
Example & Parameters
{
"source": { "path": "/documents/confidential.pdf" },
"user_password": "secret123",
"allow_print": "none",
"allow_copy": false
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
source |
对象 | 是 | -- | PDF源 |
user_password |
string | 是 | -- | 打开PDF的密码 |
owner_password |
string | 否 | 用户密码 | 更改权限的密码 |
allow_print |
string | 否 | "full" |
"full" · "low" · "none" |
allow_copy |
boolean | 否 | 真 | 允许复制文本/图像 |
allow_modify |
boolean | 否 | true | 允许修改文档 |
output_path |
string | 否 | -- | 将输出保存到文件 |
password |
string | 否 | -- | 源PDF的密码(如果已加密) |
🔓 unprotect_pdf
从加密的PDF中删除密码保护。
Example & Parameters
{
"source": { "path": "/documents/protected.pdf" },
"password": "secret123",
"output_path": "/output/unprotected.pdf"
}
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
source |
对象 | 是 | -- | PDF源 |
password |
string | 是 | -- | 加密PDF的密码 |
output_path |
string | 否 | -- | 将输出保存到文件 |
📦 MCP资源
将配置目录中的PDF作为MCP资源公开,以便直接发现和阅读客户端。
Configuration & Details
启用资源
# Command line
pdf-mcp-server --resource-dir /documents --resource-dir /data/pdfs
# Short form
pdf-mcp-server -r /documents -r /data/pdfs
# Environment variable (path-separated: colon on Unix, semicolon on Windows)
PDF_RESOURCE_DIRS=/documents:/data/pdfs pdf-mcp-server
克劳德桌面与资源:
{
"mcpServers": {
"pdf": {
"command": "npx",
"args": ["@paradyno/pdf-mcp-server", "--resource-dir", "/documents"],
"env": {
"PDF_RESOURCE_DIRS": "/data/pdfs:/shared/documents"
}
}
}
}
这两种方法可以结合使用——命令行参数被添加到环境变量路径中。
资源URI
PDF文件已公开 file:// URI:
file:///documents/report.pdf
file:///documents/2024/invoice.pdf
运营
resources/list--返回所有包含URI、名称、MIME类型、大小和描述的PDFresources/read--返回提取的文本内容,格式化以供LLM使用
资源vs工具vs缓存
| 功能 | 目的 | 用例 |
|---|---|---|
| 资源 | 被动文件发现 | 浏览和预览可用的PDF |
| 工具 | 主动PDF处理 | 提取、搜索、操作PDF |
| CacheRef | 工具链 | 在操作之间传递输出 |
🔒 安全
Configuration & Details
路径沙盒
当 --resource-dir 如果指定了,所有文件操作(读取和写入)都将沙盒到配置的目录中。路径遍历尝试(例如。, ../../etc/passwd)被封锁通过 canonicalize().
没有 --resource-dir,允许所有路径(向后兼容)。
SSRF保护
默认情况下,会检查URL源的SSRF。解析为私有或保留IP地址的URL被阻止:
- 环回(
127.0.0.0/8,::1) - 私人(
10/8,172.16/12,192.168/16,fc00::/7) - 链接本地(
169.254/16,fe80::/10)--阻止云元数据端点 - Cgnat(
100.64/10) - 广播,未指定
使用 --allow-private-urls 或 PDF_ALLOW_PRIVATE_URLS=1 禁用此检查(例如用于本地开发)。
资源限制
| 限制 | 默认值 | CLI标志 | 环境变量 |
|---|---|---|---|
| URL下载大小 | 100 MB | --max-download-size |
PDF_MAX_DOWNLOAD_BYTES |
| 缓存总字节数 | 512 MB | --cache-max-bytes |
PDF_CACHE_MAX_BYTES |
| 缓存条目 | 100 | --cache-max-entries |
PDF_CACHE_MAX_ENTRIES |
| 图像比例因子 | 10.0 | --max-image-scale |
PDF_MAX_IMAGE_SCALE |
| 图像像素面积 | 100M | --max-image-pixels |
PDF_MAX_IMAGE_PIXELS |
🔗 缓存
当 cache: true 如果指定了,服务器将返回 cache_key 用于后续请求:
// Step 1: Extract with caching
{ "sources": [{ "path": "/documents/large.pdf" }], "cache": true }
// Step 2: Use cache_key from response
{ "sources": [{ "cache_key": "a1b2c3d4" }], "pages": "50-60" }
🏗️ 建筑
block-beta
columns 1
block:server["MCP Server (rmcp)"]
columns 3
extract_text search split_pdf
end
block:common["Common Layer"]
columns 3
Cache["Cache Manager"] Source["Source Resolver"] Batch["Batch Executor"]
end
block:pdf["PDF Processing"]
columns 2
PDFium["pdfium-render\n(reading)"] qpdf["qpdf FFI\n(manipulation)"]
end
server --> common --> pdf
⚡ 演出
以一篇14页的技术论文为基准(tracemonkey.pdf,约1 MB)在Docker(苹果硅)上:
| 操作 | 时间 | 这意味着什么 |
|---|---|---|
| 提取文本 (14页) | 170毫秒 | 每分钟处理约80个文档 |
| 仅元数据 | 0.26毫秒 | 每秒约4000个文档 |
| 搜索 | 0.01 ms | 提取文本的即时结果 |
| 100个文件批处理 | 4.8秒 | 每秒约21个文档 |
关键要点
- 足够快,适合交互式使用 --文本提取在200毫秒内完成
- 元数据几乎是即时的 --使用
extract_metadata或summarize_structure在全面处理之前快速评估文档 - 搜索速度极快 --提取文本后,搜索基本上是免费的
- 批处理呈线性扩展 --处理多个文件时没有明显的开销
自己运行基准测试:
docker compose --profile dev run --rm bench
🧑💻 发展
Docker (Recommended)
# Build
docker compose --profile dev run --rm dev cargo build
# Run tests
docker compose --profile dev run --rm test
# Run tests with coverage
docker compose --profile dev run --rm coverage
# Format code
docker compose --profile dev run --rm dev cargo fmt --all
# Lint
docker compose --profile dev run --rm clippy
# Performance benchmarks
docker compose --profile dev run --rm bench
# Build production image (~120MB)
docker compose --profile prod build production
# Clean up
docker compose --profile dev down --rmi local
Native Development
需要在本地安装PDFium。下载自 pdfium二进制文件 并设置 PDFIUM_PATH.
cargo build --release
cargo test
cargo bench
cargo llvm-cov --html
Project Structure
src/
├── main.rs # Entry point, CLI args
├── lib.rs # Library root
├── server.rs # MCP server & tool handlers
├── error.rs # Error types
├── pdf/
│ ├── reader.rs # PDFium wrapper (text, metadata, outline)
│ ├── annotations.rs # Annotation extraction
│ ├── images.rs # Image extraction
│ └── qpdf.rs # qpdf FFI (split, merge, encrypt)
└── source/
├── resolver.rs # Path/URL/Base64 resolution
└── cache.rs # LRU caching layer
🗺️ 路线图
Completed Phases
第一阶段:核心阅读✅
extract_text·extract_outline·search·extract_media·extract_annotations·图像提取·批处理·缓存
第二阶段:PDF操作✅
split_pdf·合并_pdfs·保护_pdf·取消保护_pdf、压缩_pdf·提取链接·获取页面信息
第2.5阶段:LLM优化文本✅
动态阈值·段落检测·多列布局·水印去除
第2.6阶段:发现与资源✅
list_pdfs·MCP资源·资源目录配置
第2.7阶段:愿景与形式✅
convert_page_to_image·extract_form_fields·fill_form·summarize_structure
第3阶段:高级功能(计划中)
rotate_pages--旋转特定页面extract_tables--结构化表提取add_watermark--文本/图像水印linearize_pdf--Web优化- OCR支持·PDF/A验证·数字签名验证
Waiting for MCP Protocol
当前解决方法:共享文件系统(path),具有预签名URL的对象存储(url),或base64编码。
Deferred Features
这些为LLM用例提供了有限的价值:
- 断字合并 --LLMs理解连字符单词
- 固定间距模式 --有限的用例
- 边界框输出 --LLM不需要坐标
- 删除不可见文本 -pdfium-render API不支持
📄 许可证
Apache许可证2.0
