mcpField
M
MintPDF

MintPDF

远程服务
github.com/TrendTweekers生产力11 周前更新
代码仓库

关于 MintPDF

MintPDF 通过 API 或托管服务将 HTML、Markdown 和公开网页转换为样式化 PDF,适合需要生成文档的 Agent 和开发者。它支持分页控制,也可依据 MIT 许可自行部署。

主要功能

  1. 01将 HTML 和 Markdown 转为 PDF
  2. 02渲染公开 URL
  3. 03分页与重复表格标题
  4. 04页面尺寸、边距和方向
  5. 05页眉、页脚与页码选项
  6. 06自行托管部署

适用场景

  1. 01将 Markdown 简报生成 PDF
  2. 02生成带页码的 HTML 发票
  3. 03将公开网页转换为 PDF
  4. 04在私有部署中运行文档渲染

MCP 相关

通过无状态的 streamable-HTTP MCP 端点提供 `generate_pdf`(HTML 或 Markdown)和 `pdf_from_url`(公开网页)。两者均返回临时下载链接。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://mintpdf.dev/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npmmintpdf-mcp0.1.3

工具

2
参数类型必填说明
htmlstring否要渲染的完整 HTML 文档或片段
formatenum否纸张尺寸,默认为 A4A4 | Letter | Legal | A3 | A5
marginstring否四周的页边距,例如 "18mm"
markdownstring否使用默认样式表渲染的 Markdown 内容
landscapeboolean否横向页面方向,默认为 false
footerTextstring否每页显示的小号页脚文本
headerTextstring否每页上的小型页眉文本
pageNumbersboolean否在页脚显示页码

详细介绍

MintPDF

MintPDF

HTML 和 Markdown → PDF,提供 REST API 和 MCP 服务。

没有模板编辑器。没有模板 ID。没有控制面板。试用无需注册。

mintpdf.dev

立即试用 · MCP 配置 · API · 自托管 · 安全 · 限制


发送 HTML 或 Markdown,即可获取 PDF。底层使用 Chromium,并已配置好打印 CSS,因此表格不会跨页拆分、表头会重复,Markdown 的呈现效果也更像文档,而不是文本文件。

  • 分页是核心。 break-inside、重复的 thead、孤行和寡行控制,以及能真正继承你的样式的页眉和页脚。参见工作原理。
  • 原生支持 MCP — 通过可流式传输的 HTTP 提供 generate_pdf 和 pdf_from_url,让 Agent 能在对话过程中生成文档。
  • 不保留文档 — 渲染的文件会在一小时后删除,其内容绝不会被记录。密钥、电子邮件和使用量计数当然会被保存。参见安全。
  • 自行运行 — 采用 MIT 许可证,并提供已发布的镜像。提供托管服务,是为了让你无需自行运行 Chromium,而不是因为渲染器是机密。

快速入门

无需注册,也无需密钥:

curl -X POST https://mintpdf.dev/v1/pdf \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Invoice #42\n\n| Item | Price |\n|---|---|\n| Widget | $9.00 |","pageNumbers":true}' \
  --output invoice.pdf

每天渲染次数超过 3 次?免费密钥(仅需电子邮件,无需银行卡)可将额度提高到每月 100 次:

curl -X POST https://mintpdf.dev/v1/keys \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'
# → {"key":"pm_…","daily_limit":100}   # 100 renders per month

然后在请求中发送 Authorization: Bearer pm_…。

从 Claude(或任何 MCP 客户端)使用

{
  "mcpServers": {
    "mintpdf": {
      "command": "npx",
      "args": ["-y", "mintpdf-mcp"]
    }
  }
}

想直接使用托管端点?改用 mcp-remote:

{
  "mcpServers": {
    "mintpdf": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mintpdf.dev/mcp"]
    }
  }
}

重启客户端,然后直接提出请求:

“把这段讨论总结成一页简报,添加页码,并生成 PDF。”

工具输入返回
generate_pdfhtml 或 markdown,以及选项下载 URL,有效期 1 小时
pdf_from_urlurl(公开的 http/https 地址),以及选项下载 URL,有效期 1 小时

API

POST /v1/pdf

请求正文必须且只能包含一个来源,以及选项:

字段类型说明
htmlstring完整文档或片段
markdownstring使用默认样式表进行渲染
urlstring要渲染的公开页面。私有或内部地址会被阻止
formatstringA4(默认)、Letter、Legal、A3、A5
landscapeboolean默认值为 false
marginstring四边边距,例如 "18mm"
headerText / footerTextstring显示在每页上的小字
pageNumbersboolean在页脚添加 3 / 7
output"pdf" | "url"默认返回 PDF 字节;"url" 返回包含链接的 JSON
POST /v1/keys

{"email":"[email protected]"} → 获取免费密钥。无需银行卡,也无需反复验证。

POST /mcp

MCP 可流式传输的 HTTP 端点,无状态。功能与 REST API 相同。

Postman

postman/ 中提供了一个现成的集合,涵盖所有端点和选项。通过链接导入:

https://raw.githubusercontent.com/TrendTweekers/mintpdf/main/postman/mintpdf.postman_collection.json

第一个请求完全无需密钥,获取免费密钥时会自动将其保存到集合变量中,因此集合中的其余请求随后即可直接使用。

限额

套餐限额价格
匿名每个 IP 每天 3 次渲染免费,无需注册
免费密钥每月 100 次渲染免费,仅需电子邮件
Solo每月 3,000 次渲染$19/月
Team每月 12,000 次渲染$49/月
Scale每月 50,000 次渲染$129/月

自托管

MintPDF 采用 MIT 许可证;如果你更愿意,也可以运行自己的实例。

npm install
npm run build
npm start                # http://localhost:3000
node dist/smoke.js       # end-to-end render check

或者拉取已发布的镜像,其中已打包 Chromium 和字体:

docker run -p 3000:3000 \
  -e BASE_URL=http://localhost:3000 \
  -e DATA_DIR=/data -v mintpdf-data:/data \
  ghcr.io/trendtweekers/mintpdf:latest

这样,你在自己的机器上就能使用相同的 API,没有限制,也不会有任何数据离开本机:

curl -X POST http://localhost:3000/v1/pdf \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Local","pageNumbers":true}' --output local.pdf

CI 会在每次变更时构建并发布镜像,并在打标签前通过启动容器并从中渲染真实 PDF 来进行冒烟测试。标签为 latest 和短提交 SHA。你也可以自行构建:

docker build -t mintpdf .
docker run -p 3000:3000 -e BASE_URL=http://localhost:3000 mintpdf

环境变量:BASE_URL(用于下载链接)、DATA_DIR(默认为 /tmp/mintpdf;挂载卷以持久保存密钥)、ANON_DAILY_LIMIT、FREE_MONTHLY_LIMIT、SOLO_MONTHLY_LIMIT、TEAM_MONTHLY_LIMIT、SCALE_MONTHLY_LIMIT、OVERAGE_FACTOR、RENDER_CONCURRENCY、RENDER_QUEUE、RENDER_QUEUE_WAIT_MS。

负载与准入控制

每次渲染都会占用一个 Chromium 标签页,因此内存会远早于 CPU 或成本限制并发量。如果不加限制,流量激增时,每个请求都会打开一个标签页,直到 OOM 回收器终止容器,导致所有请求失败,包括那些几乎已完成的请求。在此环境中的实测结果:30 个并发渲染在没有限制的情况下留下了 30 个孤立的 Chrome 进程,机器也无法使用。

RENDER_CONCURRENCY 个渲染任务可同时运行,另有 RENDER_QUEUE 个任务可以等待;超出部分会立即被拒绝,返回 503 和 Retry-After,而不是让请求不断堆积。与其让所有人都等待到超时,不如在一秒内拒绝部分调用。

代码默认值较为保守(3 和 20)。在一个小型 Railway 实例上测得,设置为 10 和 70 时:

突发请求数已处理已拒绝中位数总耗时实例状态
454501.5s2.3s健康
12081393.0s4.0s健康
250801703.4s4.4s健康,主页响应时间为 0.24s

持续负载下,每秒大约可处理 18 次渲染,被拒绝的请求会在 2.7s 内得到响应。只有在自己的实例规格上进行实测后,才提高这些数值,切勿凭空猜测。

如果你需要更完整的自托管 PDF 工具链(Office 格式、合并、拆分),Gotenberg 是很棒的选择,功能也比这里更丰富。

安全

本服务会渲染任何人提供的 HTML 和 URL,因此需要关注的是这些内容能访问什么。

提交的 HTML 会执行 JavaScript。 这是必需的:页面会渲染 Mermaid 图表和 KaTeX 数学公式。因此,应将渲染器视为在运行不受信任的代码,这也是下文的网络限制比静态转换器更重要的原因。

SSRF 在两层防护下会被阻止。

  1. 系统会解析提交的 url,将协议限制为 http/https,并解析其地址。如果解析出的地址中 有任何一个 是私有地址,就会在启动浏览器之前拒绝请求并返回 400。
  2. Chromium 发出的每个请求都会被单独拦截,并在请求发出时再次解析目标地址;如果地址是私有地址,就会阻止请求。这不仅适用于你请求的 URL,也涵盖嵌入的图片、样式表、字体、重定向,以及提交的 JavaScript 中的 fetch()。

第二层会解析地址,而不是信任主机名,并且只缓存拒绝结果,从不缓存通过结果:缓存“此主机是公共地址”会重新打开这项检查旨在堵住的漏洞。无法解析的名称会被默认拒绝。

准确来说,这些措施的效果有其边界:DNS 重绑定攻击无法再等待缓存的通过结果过期,因此必须在每次请求中与 Chromium 自身的解析抢先完成。这比固定的时间窗口更难利用,但只是缩小了竞速范围,并未彻底关闭漏洞。要彻底消除该风险,就必须在套接字层固定解析出的地址,目前尚未实现。

会被阻止的地址包括:回环地址、0.0.0.0、RFC1918、CGNAT(100.64/10)、链路本地地址和云元数据地址(169.254.169.254);IPv6 回环地址、未指定地址、链路本地地址、站点本地地址、唯一本地地址、组播地址、NAT64 和 Teredo;两种写法的 IPv4 映射和 IPv4 兼容地址,因此 ::ffff:10.0.0.1 和 ::ffff:a00:1 是同一地址,都会被拒绝;localhost/.local/.internal 名称;解析到私有地址的任何公共主机名;以及除 http、https、data 和 blob 之外的所有协议。

地址会根据其字节进行判断,而不是匹配文本,因为同一地址有多种写法,文本匹配只能识别其中一种,遗漏其余写法。

我们为此编写了专门的测试套件,应该实际运行,而不是只相信它:

BASE=https://mintpdf.dev node scratchpad/ssrf_suite.mjs

它会检查上述绕过方式,也会检查常规渲染仍然正常,因为连网页字体也一起拦截的防护措施只是另一个 bug,并非修复。

IPv6 解析器还有一组专门针对恶意字面量的测试,因为在这类代码中,失效情形是无效字符串悄然变成有效地址:

node scratchpad/ipv6_table_test.mjs

下载链接使用 crypto.randomUUID() 标识符,且未经身份验证:在文件存在的一小时内,任何拥有链接的人都能获取文件。这是有意为之,因此可以通过电子邮件发送链接,或将链接交给浏览器;但这也意味着链接本身就是秘密。

日志记录。 会记录请求元数据(方法、路径、状态、耗时)。绝不记录请求正文,因此你发送的 HTML 和 Markdown 除临时文件外不会写入任何地方。分析表会存储事件类型、路径、来源页、国家/地区以及使用每日盐值生成的 IP 哈希值。不会存储文档内容,也无法据此还原文档。

局限

使用前值得了解。

  • 文件会在一小时后删除。 没有文档库,也无法稍后再次获取已渲染的文件。生成、使用、完成。如果需要永久保存,请在你自己的设备上保存文件内容。
  • 不支持 Office 格式、合并或拆分。 此工具仅转换 HTML、Markdown 和网页,不支持其他格式。如果你要可自托管且需要更多功能的方案,Gotenberg 更成熟,支持的功能也多得多。
  • 仅支持一个实例。 密钥和配额存储在挂载卷中的 SQLite 数据库里,因此多个副本共用一个卷无法正常工作。要进行水平扩展,必须先接入真正的数据库。
  • 渲染请求受准入控制。 超出容量时,API 会返回带有 Retry-After 的 503,而不是无限排队。实测表现请参见上表。
  • 写作时仅上线两天,尚无付费用户。

工作原理

使用 TypeScript、Fastify 和 Puppeteer,通过一个共享的 Chromium 为每个请求打开一个页面。node:sqlite 用于存储密钥、配额和事件,因此无需构建原生依赖。

实际花费精力的部分并不起眼:

  • 打印 CSS。 对表格、行、列表项、代码块、引用和图表使用 break-inside: avoid;设置 thead { display: table-header-group } 以便重复显示表头;使用 orphans/widows;对标题使用 break-after: avoid,避免标题孤零零地留在页面底部。
  • 页眉和页脚模板与页面是分开的文档:它们会忽略页面 CSS,如果样式未内联,字体大小几乎为零;并且位于内容边距之外。
  • 准入控制,因为每个并发请求对应一个 Chromium 标签页,容器很容易因此耗尽内存。
  • 网络隔离,用于运行不受信任 JavaScript 的渲染器。请参见“安全性”。

许可证

MIT——请参见 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。