mcpField
M
MintPDF

MintPDF

リモート
github.com/TrendTweekers生産性11 週間前に更新
リポジトリ

MintPDF について

MintPDFは、APIまたはホステッドサービスを通じてHTML、Markdown、公開ウェブページをスタイル付きPDFに変換します。ページ分割を調整したいエージェントや開発者向けで、MITライセンスのもとセルフホストも可能です。

主な機能

  1. 01HTMLとMarkdownのPDF変換
  2. 02公開URLのレンダリング
  3. 03ページ分割と表見出しの繰り返し
  4. 04用紙サイズ、余白、向きの設定
  5. 05ヘッダー、フッター、ページ番号
  6. 06セルフホストでのデプロイ

活用シーン

  1. 01Markdownの概要をPDF化
  2. 02ページ番号付きHTML請求書の生成
  3. 03公開ウェブページをPDFに変換
  4. 04プライベート環境でドキュメントをレンダリング

MCP 対応

ステートレスなstreamable-HTTP MCPエンドポイントで、HTMLまたはMarkdown用の`generate_pdf`と公開ページ用の`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 を利用できるため、エージェントは会話の途中で文書を生成できます。
  • 文書は保存されません — 生成されたファイルは 1 時間後に削除され、その内容がログに記録されることはありません。キー、メールアドレス、使用回数は当然保存されます。セキュリティをご覧ください。
  • 自分で運用できます — 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

1 日 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"]
    }
  }
}

クライアントを再起動したら、次のように依頼するだけです:

「このスレッドをページ番号付きの 1 ページの概要にまとめて、PDF にしてください。」

ツール入力戻り値
generate_pdfhtml または markdown とオプションダウンロード URL。有効期間は 1 時間
pdf_from_urlurl(公開されている http/https)とオプションダウンロード URL。有効期間は 1 時間

API

POST /v1/pdf

本文には、オプションとともにソースを必ず 1 つだけ指定します:

フィールド型備考
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 ごとに 1 日 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 件を同時にレンダリングすると、Chrome プロセスが 30 個残り、マシンが使いものにならなくなりました。

RENDER_CONCURRENCY 件を同時にレンダリングし、さらに RENDER_QUEUE 件まで待機できます。それを超えるリクエストは、滞留させずに 503 と Retry-After を返して即座に拒否します。すべてのリクエストをタイムアウトさせるより、1 秒以内に一部の呼び出しを拒否するほうが確実に優れています。

コードのデフォルト値は控えめ(3 と 20)です。小規模な Railway インスタンス 1 台で、値を 10 と 70 にして計測しました。

バースト処理済み拒否中央値経過時間インスタンスの状態
454501.5 秒2.3 秒正常
12081393.0 秒4.0 秒正常
250801703.4 秒4.4 秒正常、ホームページ 0.24 秒

拒否された分の応答時間を 2.7 秒未満に抑えつつ、毎秒およそ 18 件のレンダリングを継続できます。数値を引き上げる場合は、期待に頼らず、ご自身のインスタンスサイズで計測してからにしてください。

Office 形式、結合、分割に対応した、より包括的なセルフホスト型 PDF ツールチェーンをお探しなら、Gotenberg が優れており、これより多くの機能を備えています。

セキュリティ

このサービスは、誰でも指定できる HTML と URL をレンダリングするため、重要なのはそのコンテンツが何にアクセスできるかです。

送信された HTML は JavaScript を実行します。 Mermaid の図や KaTeX の数式をページ内にレンダリングするため、これは必要です。レンダラーは信頼できないコードを実行するものとして扱ってください。そのため、以下のネットワーク制限は静的な変換ツールの場合よりも重要です。

SSRF は 2 層でブロックされます。

  1. 送信された url を解析し、http/https に制限したうえで名前解決します。名前解決されたアドレスに 1 つでもプライベートアドレスがあれば、ブラウザーが関与する前に 400 エラーでリクエストを拒否します。
  2. 独立した対策として、Chromium が行うすべてのリクエストをインターセプトし、宛先をリクエスト時に再度名前解決して、プライベートアドレスであればブロックします。これにより、指定された URL だけでなく、埋め込み画像、スタイルシート、フォント、リダイレクト、送信された JavaScript からの fetch() も対象になります。

2 層目ではホスト名を信頼せずに名前解決し、拒否した結果のみをキャッシュし、許可した結果はキャッシュしません。「このホストはパブリック」という結果をキャッシュすると、このチェックが防ごうとしているまさにその抜け穴が再び開いてしまうためです。名前解決できない場合は、安全側に倒して拒否します。

この仕組みで実現できることとできないことを正確に説明します。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

上記の回避手法に加え、通常のレンダリングが引き続き機能することも確認します。Web フォントまでブロックするガードは、修正ではなく別のバグだからです。

IPv6 パーサーには、攻撃的なリテラルを独自にまとめたテーブルがあります。この種のコードで問題になるのは、無効な文字列がひそかに有効なアドレスとして扱われることだからです。

node scratchpad/ipv6_table_test.mjs

ダウンロードリンクには crypto.randomUUID() の識別子を使用し、認証は行いません。リンクが有効な 1 時間の間は、リンクを知っている人なら誰でもファイルを取得できます。リンクをメールで送ったり、ブラウザーに渡したりできるよう、意図的にこの方式を採用しています。ただし、リンク自体が秘密情報になります。

ログ記録。 リクエストのメタデータ(メソッド、パス、ステータス、所要時間)を記録します。リクエスト本文は一切記録されないため、送信した HTML と Markdown は一時ファイル以外には書き込まれません。分析テーブルに保存されるのは、イベントの種類、パス、リファラー、国、および日ごとにソルトを加えた IP アドレスのハッシュです。ドキュメントの内容は保存されず、そこからドキュメントを復元する方法もありません。

制限事項

利用を始める前に知っておきたい点です。

  • ファイルは1時間後に削除されます。 ドキュメントライブラリはなく、後からレンダリング結果を取得する方法もありません。生成して、使って、完了です。保存しておく必要がある場合は、データを手元に保存してください。
  • Office形式、結合、分割には対応していません。 HTML、Markdown、ウェブページを変換するもので、それ以外には対応していません。セルフホスト可能な環境で、より成熟した、幅広い用途に対応するものが必要であれば、Gotenbergをご利用ください。
  • 1インスタンスのみです。 キーとクォータはマウントされたボリューム上のSQLiteに保存されるため、1つのボリュームに対して複数のレプリカを実行しても機能しません。水平スケーリングには、まず本格的なデータベースが必要です。
  • レンダリングには受付制御があります。 容量を超えると、無制限にキューへ追加するのではなく、APIはRetry-Afterとともに503を返します。測定された動作については、上の表をご覧ください。
  • 執筆時点で公開から2日しか経っておらず、有料ユーザーはまだいません。

仕組み

TypeScript、Fastify、そしてリクエストごとに1つのページを使用する、共有のChromiumを操作するPuppeteerで構成されています。キー、クォータ、イベントの保存にはnode:sqliteを使用するため、ビルドが必要なネイティブ依存関係はありません。

実際に手間がかかったのは、目立たない次の部分です。

  • 印刷用CSS。 テーブル、行、リスト項目、コードブロック、引用、図にbreak-inside: avoidを指定し、ヘッダーを繰り返すためにthead { display: table-header-group }を指定しています。また、orphans/widowsを設定し、見出しがページの末尾に取り残されないようbreak-after: avoidを指定しています。
  • ヘッダーとフッターのテンプレートは、ページ本体とは別のドキュメントです。スタイルをインラインで記述しない限り、ページのCSSは適用されず、ほぼゼロのフォントサイズでレンダリングされます。また、コンテンツの余白の外側に配置されます。
  • 受付制御。 同時リクエストごとにChromiumのタブを1つ使用するため、コンテナのメモリが不足するのを防ぎます。
  • ネットワーク分離。 信頼できないJavaScriptを実行するレンダラーを分離します。「セキュリティ」をご覧ください。

ライセンス

MIT — LICENSEをご覧ください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。