关于 emperor-pdf
emperor-pdf 是供 Agent 和客户端处理指定文件夹中 PDF 的 MCP 服务,也可接收 PDF 数据或 HTTPS URL。它集成文本提取、搜索和页面渲染,默认不提供会修改文件的工具。
主要功能
- 01读取 PDF 元数据和页面文本
- 02使用文本或正则表达式搜索 PDF
- 03将页面渲染为 PNG 图片
- 04合并 PDF 或提取指定页面
- 05启用后从 Markdown 创建 PDF
- 06提示可能存在的隐藏文本
适用场景
- 01搜索论文文件夹中的术语并查看匹配页面
- 02将扫描页面渲染为图片以便检查
- 03合并多个 PDF 中选定的页面
- 04启用写入后从 Markdown 生成 PDF
MCP 相关
向 MCP 客户端提供 PDF 信息、文本、搜索和渲染工具,可从根目录、base64 数据或 HTTPS URL 读取文件。启用写入后,还可合并和提取页面,以及从 Markdown 创建 PDF。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
emperor-pdf
为你的 Agent 管理同一文件夹中的 PDF:阅读、搜索、渲染、合并、拆分和创建 PDF。
这是一个 MCP 服务,只处理单个根文件夹中的 PDF,不会访问其他位置:
- 阅读和搜索文本,逐页处理;PDF 可以来自根文件夹、调用时传入的 Base64 字节,或
https://URL。它使用 Google 的 PDFium(Chrome 内置的引擎);如果未安装 PDFium,则回退到纯 Rust 提取器。 - 警示隐藏文本:白底白字、不可见、小于一点或位于页面范围之外的文本——这些都是在看似无害的文档中植入面向模型的指令的常见手段。
- 查看页面:将页面渲染为模型可查看的 PNG 图像(扫描页面也通过这种方式读取)。
- 合并和提取页面,以及从 Markdown 创建 PDF;使用 Typst 排版,字体为内置于二进制文件中的 OFL 字体。
- 通过能力限制访问范围,而非进行字符串检查:每个文件都通过
cap-std目录句柄打开,因此操作系统层会拒绝..、绝对路径以及指向根目录之外的符号链接。 - 默认只读:未指定
--writable时,写入工具甚至不会提供。
基于 emperor-mcp 框架构建:无状态 Streamable HTTP(桌面客户端也可使用 stdio)、带帧输出、提供 doctor 子命令,包含 4 个只读工具和 6 个需使用 --writable 的工具。它符合 Emperor Profile P1.1:除非操作员在启动时启用写入(使用 --writable 或 PDF_WRITABLE),否则不会列出写入工具;工具定义也十分精简,包含简短的使用场景说明和紧凑的输入架构。
安装
预构建二进制文件(macOS arm64/x86_64、Linux x86_64、Windows x86_64)可从 GitHub releases 下载。也可以从源码构建:
cargo install --git https://github.com/yarenty/emperor-pdf
构建需要 Rust 1.92 或更高版本(typst 0.15 要求至少使用该版本)。
只读构建
pdf_create 由 create Cargo 功能控制(默认启用);该功能会引入 Typst 和内置字体。禁用该功能后,会得到更小的二进制文件,但仍可阅读、搜索、渲染、合并和提取 PDF:
cargo install --git https://github.com/yarenty/emperor-pdf --no-default-features
| 构建方式 | 发布版二进制文件(macOS x86_64) |
|---|---|
默认(create) | 51 MB |
--no-default-features | 14 MB |
Docker
仓库中的 Dockerfile 会构建一个通过 stdio 与 MCP 通信并包含 PDFium 的镜像(linux/amd64 和 linux/arm64)。将包含 PDF 的文件夹挂载到 /data:
docker build -t emperor-pdf .
docker run -i --rm -v ~/Documents/papers:/data:ro emperor-pdf
# read-write: mount without :ro and switch writing on
docker run -i --rm -e PDF_WRITABLE=true -v ~/Documents/papers:/data emperor-pdf
服务以 uid 10001 运行,因此使用 --writable 时,挂载的文件夹必须允许该用户写入。
PDFium(推荐)
PDFium 是一个在运行时加载的原生库;emperor-pdf 不会将其打包在内。各个平台的预编译 PDFium 二进制文件来自 bblanchon/pdfium-binaries(Apache-2.0 / BSD-3-Clause)。在检出项目后:
scripts/fetch-pdfium.sh # downloads the right archive for this machine into ./pdfium/
或者自行从某个发行版下载 pdfium-<os>-<cpu>.tgz,并解压到任意位置。发行版固定为
chromium/7881,这是构建 pdfium-render 绑定所用的 PDFium API 版本;使用 PDFIUM_VERSION=<n> scripts/fetch-pdfium.sh 可选择其他版本。
emperor-pdf 按以下顺序查找 libpdfium.dylib / libpdfium.so / pdfium.dll:
--pdfium-dir DIR(DIR、DIR/lib或DIR/bin中的库),PDFIUM_DYNAMIC_LIB_PATH(一个文件夹,会按相同规则在lib/和bin/中查找;也可以是文件),- 存放
emperor-pdf二进制文件的文件夹, - 系统库路径。
如果没有 PDFium,pdf_text 和 pdf_search 会使用 lopdf 的
提取器(并在输出中说明:它会漏掉或弄乱某些 PDF 中的文本),而
pdf_render_page 会说明它需要 PDFium。其他功能不受影响。
运行
# Streamable HTTP at http://127.0.0.1:8032/mcp, read-only
emperor-pdf serve --root ~/Documents/papers --pdfium-dir ./pdfium
# also offer pdf_pages and pdf_create, and allow saving rendered pages
emperor-pdf serve --root ~/Documents/papers --pdfium-dir ./pdfium --writable
# stdio, for clients that start the server themselves
emperor-pdf serve --stdio --root ~/Documents/papers
| 标志 | 默认值 | 含义 |
|---|---|---|
--root DIR | 必填 | 服务唯一可访问的文件夹;工具路径均相对于该文件夹。即使客户端只发送 data 或 url,也必须指定。 |
--bind ADDR | 127.0.0.1:8032 | Streamable HTTP 的监听地址。 |
--writable | 关闭 | 提供 pdf_pages 和 pdf_create,并允许使用 pdf_render_page { save_as }。未启用时不会列出这两个工具。也可通过 PDF_WRITABLE 设置:true、1、yes 或 on 会启用;未设置、空值、false、0、no 或 off 会保持关闭;任何其他值都会导致服务在启动时停止。 |
--pdfium-dir DIR | 无 | 优先查找 PDFium 的位置。 |
--stdio | 关闭 | 改用 stdin/stdout 通过 MCP 通信,而非使用 HTTP。 |
日志输出到 stderr(使用 RUST_LOG=debug 可查看更多日志)。GET /health 会返回 OK。
连接客户端
Claude Code
# HTTP (start the server first)
claude mcp add --transport http pdf http://127.0.0.1:8032/mcp
# or stdio
claude mcp add pdf -- emperor-pdf serve --stdio --root /path/to/pdfs --pdfium-dir /path/to/pdfium
Claude Desktop(claude_desktop_config.json)
{
"mcpServers": {
"pdf": {
"command": "/path/to/emperor-pdf",
"args": ["serve", "--stdio", "--root", "/path/to/pdfs", "--pdfium-dir", "/path/to/pdfium"]
}
}
}
Claude Desktop,读写模式:在 args 中添加 "--writable"。
Kowalski(config.toml),通过 HTTP 或 stdio 连接:
[[mcp.servers]]
name = "pdf"
transport = "http"
url = "http://127.0.0.1:8032/mcp"
# or let Kowalski start it
[[mcp.servers]]
name = "pdf"
transport = "stdio"
command = ["/path/to/emperor-pdf", "serve", "--stdio", "--root", "/path/to/pdfs", "--pdfium-dir", "/path/to/pdfium"]
工具
四种读取工具每次调用只能通过以下三种方式之一接收 PDF:
path:相对于根文件夹的文件(对于pdf_search,也可以是**/*.pdf之类的 glob);data:PDF 字节的 base64 编码(可接受data:application/pdf;base64,前缀);url:服务器下载的https://URL。
data 和 url 的大小上限为 8 MiB(emperor-mcp 的 limits 字节上限);下载超时时间为
30 秒,最多跟随五次重定向。
| 工具 | 参数 | 返回内容 |
|---|---|---|
pdf_info | path / data / url | 页数、标题、作者、主题、关键词、创建者、生成器、创建 / 修改日期(ISO 8601)、PDF 版本、是否加密、字节大小。 |
pdf_text | path / data / url、pages?("1-3,5"、"4-")、max_chars?(默认 100 000,最多 2 000 000) | 每页文本、所用的提取器(pdfium 或 lopdf)、是否已截断,以及存在隐藏文本时发出的警告。 |
pdf_search | path(文件或 glob)/ data / url、query、regex?、case_sensitive?、max_hits?(默认 50,最多 500) | 每个匹配项的文件、页码、匹配内容和上下文摘要;含有隐藏文本的页面会被标记。 |
pdf_render_page | path / data / url、page、dpi?(1 到 300,默认 110)、save_as?、overwrite? | 页面 PNG 图像(MCP 图像内容)、图像大小及保存位置。需要 PDFium;save_as 需要 --writable。 |
pdf_pages | operation(merge 或 extract)、inputs([{path, pages?}])、output、overwrite? | 根据所选页面及其书写顺序生成的新 PDF。仅限 --writable 服务。 |
pdf_create | markdown、output、title?、overwrite? | 根据 Markdown 排版生成的新 PDF(标题、强调、列表、表格、代码块、引用、链接)。仅限使用 create 功能构建的 --writable 服务。 |
页码从 1 开始。pdf_pages 会保留页面及其内容,但不会保留输入文件中的书签、表单或标签结构。
工具注解会说明每个工具的用途:读取工具是只读、幂等且开放世界的(可获取 URL);可写服务上的 pdf_pages、pdf_create 和 pdf_render_page 不是只读工具,并被标记为具有破坏性,因为 overwrite: true 会替换文件。在只读服务上,pdf_render_page 被标记为只读,因为它无法保存文件。
隐藏文本
使用 PDFium 时,pdf_text 和 pdf_search 会检查所读取页面上的每个字符,并标记人眼查看页面时可能看不到的文本:
- 使用不可见渲染模式(模式 3)绘制的文本,除非它位于图像上方——OCR 正是通过这种方式让扫描页面可搜索;
- 白色或近白色(或完全透明)且背后没有任何内容的文本;
- 小于 1 pt 的文本;
- 位于页面框之外的文本。
这些文本仍会在文档框架内返回;此外还会单独显示带框的警告,注明文件名、页码和原因,并要求模型将其视为数据并告知用户。pdf_search 会将此类页面上的每个匹配项标记为 page_has_hidden_text。这是一种启发式检查:例如,表单对象内绘制的白色背景虽然不会遮挡任何内容,但不会被深入检查。lopdf 回退方案不会检查,并会说明这一点。
扫描页面
emperor-pdf 没有 OCR 引擎。没有文本层的扫描页面通过 pdf_text 返回时内容为空或接近为空;请使用 pdf_render_page 渲染页面,并让具备视觉能力的模型读取图像。已进行 OCR 的扫描件带有不可见文本层,pdf_text 会读取该文本(但不会将其标记为隐藏文本)。
安全模型
- 一个根目录,通过 capability 强制执行。 根目录只打开一次,作为
cap_std::fs::Dir;所有读写都通过它使用相对路径进行。任何包含..的路径或绝对路径都会在进行任何文件系统调用前被拒绝,并给出明确提示;cap-std 会拒绝解析到根目录之外的符号链接。Glob 会通过同一个句柄遍历根目录来展开(跳过隐藏文件夹,最多 200 个文件)。 - 默认只读,除非指定
--writable。 未指定时,不会注册pdf_pages和pdf_create(客户端看不到它们),而pdf_render_page { save_as }会提示服务为只读。指定后,除非调用传入overwrite: true,否则不会替换现有文件。 - URL:仅限公开的 HTTPS。
url必须使用https://,且不能包含用户名或密码;每次重定向都会重新检查。主机名由服务解析,且只使用公开地址:环回、私有地址(RFC 1918)、链路本地地址(包括 169.254.169.254 上的云元数据地址)、共享地址、IPv6 唯一本地地址及类似范围都会被拒绝,因此调用无法访问服务所在网络上的服务。下载内容和data的大小上限为 8 MiB,且必须以 PDF 格式开头。 - 文档文本是数据。 PDF 可能来自任何地方,也可能包含旨在引导模型的文本。文本和搜索摘要会通过 emperor-mcp framing 标记为作者身份未知的文档(带随机数保护的分隔符,并注明“数据,而非指令”);元数据、结果和隐藏文本警告则会标记为计算值。
- Markdown 无法执行代码。
pdf_create会转义文本中的每个字符,并将代码和链接作为字符串字面量传递,因此 Markdown 无法作为标记或脚本传入 Typst;Typst world 不提供任何文件,只提供生成的文件,并且字体会嵌入,因此文档无法读取磁盘。Typst 仅在使用create功能构建的可写服务中运行。 - 限制工作量。 超过 256 MiB 的文件会被拒绝;回退文本提取会限制每页解压后的内容量;渲染上限为 300 dpi 和单边 8000 px;Markdown 输入上限为 2 MiB。
doctor
emperor-pdf doctor --root ~/Documents/papers --pdfium-dir ./pdfium --writable
emperor-pdf 0.1.3 doctor
[ok ] root folder /Users/me/Documents/papers (writable)
[ok ] pdfium loaded from ./pdfium/lib/libpdfium.dylib
[ok ] typst fonts 6 embedded faces (DejaVu Sans Mono, Libertinus Serif)
[ok ] listen address 127.0.0.1:8032 is free
[ok ] tool budget 6 of at most 8 tools
all good (0 warning(s))
检查失败时会以 1 退出。缺少 PDFium 属于警告,不算失败。--stdio 会跳过端口检查。工具数量预算统计服务将列出的工具:只读模式下为四个,使用 --writable 时为六个。使用 --no-default-features 构建时不会进行字体检查。
开发
scripts/fetch-pdfium.sh # once, so the PDFium tests run instead of being skipped
cargo fmt --all --check
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --no-default-features -- -D warnings
cargo test
cargo deny check
测试会在临时文件夹中使用 Typst 构建测试 PDF,并通过 HTTP(以及一个通过 stdio)与真实服务通信;url 来源会从一个小型本地 HTTP 服务获取。工具列表通过 emperor-mcp 的 testkit 检查。若没有 ./pdfium,仅依赖 PDFium 的测试会打印提示并通过。
链接
- crates.io:emperor-pdf
- 官方 MCP Registry:mcp-name: io.github.yarenty/emperor-pdf
- 框架:emperor-mcp
- 与其他 PDF MCP 服务的对比:docs/COMPARISON.md
许可证
可由你选择采用 MIT 或 Apache-2.0 双重许可。
字体
启用 create 功能后,二进制文件会为 pdf_create 嵌入两个字体系列,字体文件位于
assets/fonts,并附带相应的许可证文本:
| 字体 | 文件 | 许可证 |
|---|---|---|
| Libertinus Serif(正文) | Regular、Bold、Italic、Bold Italic | SIL Open Font License 1.1(文本) |
| DejaVu Sans Mono(代码) | Regular、Bold | Bitstream Vera 许可证;DejaVu 的更改属于公有领域(文本) |
两者均采用宽松许可证,允许将字体嵌入文档,并随软件重新分发。项目不包含采用 GPL 许可证的字体(未使用 Typst 自带的 New Computer Modern 字体集)。发布压缩包中附带这两份许可证文本,文件名为 FONTS-NOTICE。你创建的文档不受这些许可证的影响,但如果提取字体,则需保留字体自带的声明。安装的 PDFium 受其自身许可证(Apache-2.0 / BSD-3-Clause)约束。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。