PDF处理服务器

一个高性能的PDF处理服务器,支持文本提取、搜索、分割、合并、加密等功能。

  • by paradyno
  • Rust
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 paradyno/PDF-MCP-Server

使用说明

📄 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类型、大小和描述的PDF
  • resources/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
  • 大文件上传 -MCP缺少用于上传大文件(>20MB)的标准API。讨论于 #1197, #1220, #1659.
  • 分块文件传输 --目前还没有标准机制。

当前解决方法:共享文件系统(path),具有预签名URL的对象存储(url),或base64编码。

Deferred Features

这些为LLM用例提供了有限的价值:

  • 断字合并 --LLMs理解连字符单词
  • 固定间距模式 --有限的用例
  • 边界框输出 --LLM不需要坐标
  • 删除不可见文本 -pdfium-render API不支持

📄 许可证

Apache许可证2.0

🙏 致谢

  • PDFium --PDF渲染引擎(Apache 2.0)
  • pdfium渲染 --Rust PDFium绑定(Apache 2.0)
  • qpdf --PDF转换库,通过FFI(Apache 2.0)提供
  • rmcp --Rust MCP SDK