Python MCP サーバー
NextPDF Python SDK には、PDF 抽出操作をエージェントのネイティブツールとして公開する Model Context Protocol(MCP)サーバーが付属しています。MCP 対応のエージェント(たとえば Claude Code)は、このサーバーを一度登録すれば、以後は他のツールと同じ方法で NextPDF ツールを呼び出せます。
このサーバーは軽量なアダプターです。各ツールはローカルディスクから PDF を読み込み、NextPDF Connect エンドポイントに非同期クライアントで問い合わせ、結果を JSON 文字列として返します。サーバー自体にビジネスロジックはなく、呼び出し間でデータを保存しません。
MCP エクストラ付きで SDK をインストールします。
pip install nextpdf[mcp]インストールされる mcp エクストラは、アップストリームの mcp パッケージ(制約 mcp>=1.0,<2.0)を追加します。サーバーには Python 3.10 以降が必要です。
MCP クライアントの構成からサーバーモジュールを実行します。次の例では、構成ファイルにシークレットを埋め込まず、2 つの接続値をどちらもホスト環境から読み込みます(セキュリティを参照)。
{ "mcpServers": { "nextpdf": { "command": "python", "args": ["-m", "nextpdf.mcp"], "env": { "NEXTPDF_BASE_URL": "https://connect.example.com", "NEXTPDF_API_KEY": "${NEXTPDF_API_KEY}" } } }}この python -m nextpdf.mcp エントリポイントは main() を実行し、asyncio.run(serve()) を介して標準入出力(stdio)上でサーバーを起動します。python -m nextpdf と混同しないでください。こちらは MCP サーバーではなく、コマンドラインインターフェイス(CLI)を実行します。
NEXTPDF_BASE_URL と NEXTPDF_API_KEY はどちらも必須です。サーバーは最初のツール呼び出し時にクライアントを遅延初期化します。いずれかの変数が空の場合は RuntimeError を送出し、プロセスをクラッシュさせるのではなく、ツールエラーとしてエージェントへ返します。
ツールカタログと SDK のマッピング
「ツールカタログと SDK のマッピング」という見出しのセクションサーバーは 8 個のツールを登録します。すべてのツール名には nextpdf_ プレフィックスが付きます。各ツールは非同期クライアントの ast 名前空間(AsyncNextPDF.ast)のメソッドにマップされます。ただし、下に示す 2 つの複合ツールは例外で、下位レベルの呼び出しをサーバー内部で組み立てます。
| MCP ツール | SDK 呼び出し | 備考 |
|---|---|---|
nextpdf_extract_text | ast.extract_cited_text(pdf_data, page_index=..., headings_only=...) | 返却値は CitedTextBlock のリスト。 |
nextpdf_extract_tables | ast.extract_cited_tables(pdf_data, page_range=...) | 応答は ExtractCitedTablesResponse。 |
nextpdf_get_ast | ast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...) | 応答は AstDocument。 |
nextpdf_info | ast.get_document_ast(pdf_data) | サーバー側で組み立てるメタデータ要約。専用エンドポイントなし。 |
nextpdf_health | なし | 環境変数のみの検査。ネットワーク呼び出しなし。 |
nextpdf_search | ast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...) | 応答は SearchAstNodesResponse。 |
nextpdf_get_outline | ast.search_ast_nodes(pdf_data, node_type="heading", max_results=500) | サーバー側で見出しノードをアウトライン化。 |
nextpdf_diff | ast.get_ast_diff(original_pdf_data, modified_pdf_data) | 応答は GetAstDiffResponse。 |
エージェントを接続する前に、ツール入力について次の点を把握しておいてください。
- すべてのパス入力(
pdf_path、original_pdf_path、modified_pdf_path)は、サーバーを実行しているマシン上のファイルへの絶対パスです。エージェントはパスを渡し、サーバーは該当ファイルのバイト列をローカルで読み込みます。アップロード用のツールはありません。 nextpdf_extract_textは入力スキーマでmax_pagesフィールドを宣言しますが、テキストハンドラーはこれを SDK に渡しません。テキスト抽出の対象ページはpage_index(0 始まりの単一ページ)で指定します。ドキュメント全体の走査を制限する必要がある場合は、max_pagesを指定してnextpdf_get_astを使用してください。nextpdf_get_astはmax_pagesを、両端を含むページ範囲[0, max_pages - 1]に変換します(max_pagesの既定値は 50 です)。返されるツリーのサイズを制限するにはtoken_budgetを渡します。nextpdf_infoはschema_version、source_hash、page_count、estimated_tokens、root_node_type、およびroot_children_countを返します。これらはAstDocumentモデルに由来し、estimated_tokensは計算済みプロパティです(トークンあたりおおよそ 4 文字)。nextpdf_get_outlineは見出しごとに 1 エントリを返し、各エントリにはid、page_index、text、およびdepth(ノードのattributes["level"]から読み取られ、既定値は 1)が含まれます。さらにheading_count、total_matches、およびtruncatedも返します。
引用抽出ツールは、すべての結果に CitationAnchor を付加します。各アンカーは node_id、page_index、正規化された bbox(座標は 0.0 から 1.0 の範囲)、および confidence スコア(0.0 から 1.0)を保持します。来歴(プロベナンス)を必要とするエージェントでは、生のテキストだけでなく、これらのフィールドも提示するようにしてください。
エラー処理、タイムアウト、クォータ
「エラー処理、タイムアウト、クォータ」という見出しのセクションサーバーは、例外がエージェントトランスポートへ伝播することを決して許しません。call_tool ディスパッチャーはすべてのエラーを捕捉して JSON TextContent として返すため、失敗したツール呼び出しは接続切断ではなく、エージェントが読み取れる構造化ペイロードになります。ペイロードの形式は次のとおりです。
| 条件 | 返される JSON |
|---|---|
| 不明なツール名 | {"error": "Unknown tool: <name>"} |
| 入力ファイルが存在しない | {"error": "PDF file not found: <path>"} |
すべての NextPDFError サブクラス | {"error": "<message>", "error_type": "<class>", "status_code": <int?>} |
| その他の例外 | {"error": "Unexpected error: <message>"} |
status_code は、基になるエラーが値を持つ場合にのみ含まれます。SDK は HTTP レスポンスを型付き例外階層にマップし、その階層はすべて NextPDFError を起点とします。
| 例外 | HTTP ステータス | error_code | 発生条件 |
|---|---|---|---|
NextPDFLicenseError | 402 | license/tier-required | エンドポイントで、より高いサーバー側ライセンスティアが必要な操作。 |
AstNoStructTreeError | 422 | ast/no-struct-tree | タグのない PDF で、サーバー側のヒューリスティックフォールバックが無効。 |
QuotaExceededError | 429 | quota/exceeded | レート制限またはクォータ到達。サーバーが Retry-After ヘッダーを送信した場合のみ、retry_after(秒)を保持。 |
AstBuildTimeoutError | 504 | ast/build-timeout | AST 構築がサーバーの時間予算を超過。ページ範囲の縮小が必要。 |
NextPDFAPIError | その他の 4xx/5xx | サーバー提供 | その他の API レベルの障害。 |
エージェント連携での実践的なガイダンスを示します。
- タイムアウト。 HTTP クライアントは固定の既定タイムアウト(合計 60 秒、接続タイムアウト 10 秒)を使用します。低速または大容量のドキュメントでは、
AstBuildTimeoutError(サーバーが AST の構築を断念した場合)として現れることがあります。クライアント自体がタイムアウトした場合は、トランスポート層からのUnexpected errorペイロードとして現れます。ast/build-timeoutが表示された場合は、エージェントにスコープを絞るよう指示してください。max_pagesをnextpdf_get_astで下げるか、抽出ツールでpage_index/page_startとpage_endを設定します。 - クォータとバックオフ。 429 が発生すると、ツールは
error_typeとしてQuotaExceededErrorを、status_codeとして 429 を返します。retry_afterの値は例外オブジェクト上に存在します。サーバーはerror、error_type、およびstatus_codeのみをシリアライズするため、エージェントはツール出力から再試行ヘッダーを解析しようとせず、429 を一時停止して後で再試行するシグナルとして扱うべきです。クォータはエージェントではなく、Connect エンドポイントで適用してください。 - タグなし PDF。 422
ast/no-struct-treeは、ソース PDF に構造ツリーがないことを意味します。このようなドキュメントでは、サーバーでヒューリスティックモードを有効にするか、抽出前にタグ付けステップへ回してください。
セキュリティ: API キーのスコープ設定と最小権限
「セキュリティ: API キーのスコープ設定と最小権限」という見出しのセクションAPI キーは、データベースパスワードと同じ注意が必要なシークレットとして扱ってください。
- MCP 構成ファイルにキーを絶対に埋め込まないでください。 上記の JSON 例は
${NEXTPDF_API_KEY}を参照しており、値は起動時にホスト環境またはシークレットマネージャーから resolve(解決)されます。構成ファイルはソース管理にコミットされても、シークレットはコミットされてはなりません。 - キーを読み取り専用の抽出にスコープ設定してください。 MCP サーバーは AST 抽出のサーフェス(
extract_cited_text、extract_cited_tables、get_document_ast、search_ast_nodes、get_ast_diff)のみを呼び出します。レンダリング、署名、墨消し、ドキュメントの変更は一切行いません。エージェントには、サーバー側スコープがこれらの読み取りパスに限定されたキーを発行してください。そうすれば、侵害されたエージェントが書き込みや上位ティアの操作へアクセスできなくなります。 - エージェントごとに専用のキーを使用してください。 エージェントごとのキーを使うと、他の連携に影響を与えずに 1 つの連携だけを失効またはローテーションでき、エンドポイントのログを特定のエージェントに帰属させられます。
- ファイルシステムを制約してください。 すべてのツールはローカルディスクから絶対パスを読み込むため、サーバーはホストプロセスが読み取れる任意のファイルを読み取れます。非特権ユーザーとして実行し、作業ディレクトリをドキュメントフォルダーに制限し、特権アカウントでは決して実行しないでください。
- Transport Layer Security(TLS)を優先してください。 ローカル以外のデプロイでは、
NEXTPDF_BASE_URLをhttps://エンドポイントに向けてください。SDK はキーをBearerトークンとしてAuthorizationヘッダーで送信するため、平文トランスポートでは通信経路上でキーが露出します。
これらのクライアント側プラクティスを支えるエンドポイント側の制御については、Connect のセキュリティと運用を参照してください。
エージェント接続前のローカルでのサーバーテスト
「エージェント接続前のローカルでのサーバーテスト」という見出しのセクションエージェントを接続する前に、サーバー単体で検証してください。最も速いチェックには PDF もネットワークも不要です。
python -c "from nextpdf.mcp import _tool_definitions; print(len(_tool_definitions()))"正しくインストールされていれば 8 が出力されます。ImportError が表示され、mcp エクストラに言及している場合は、オプション依存関係が不足しています。pip install nextpdf[mcp] で再インストールしてください。
次に、ツールが使用するものと同じ SDK パスを CLI 経由で実行します。CLI は同じ 2 つの環境変数を使ってエンドポイントと通信します。これらを一度設定します。
export NEXTPDF_BASE_URL="https://connect.example.com"export NEXTPDF_API_KEY="$(cat /run/secrets/nextpdf_api_key)"次に、バージョン、接続性、実際の抽出を確認します。
nextpdf versionnextpdf info /path/to/sample.pdfnextpdf extract text /path/to/sample.pdf --headings-onlynextpdf version は資格情報なしで実行でき、パッケージをインポートできることを確認します。nextpdf info は get_document_ast を実行します。これは nextpdf_get_ast と nextpdf_info の背後にある呼び出しと同じです。両方が成功すれば、資格情報とエンドポイントは正しく、対応する MCP ツールも動作します。
MCP プロトコルを直接操作するには、アップストリームの MCP Inspector(mcp パッケージに同梱)を使用します。エージェントが使用するのと同じコマンドと環境に向けて、ツールを手動で一覧表示し、呼び出します。nextpdf_health が status: "ok" を報告することを確認してください。misconfigured を返すのは、NEXTPDF_BASE_URL または NEXTPDF_API_KEY が未設定のときで、これはエージェントが実際のツールを呼び出す前に環境値の不足を捉える最も手早い方法です。
ツール呼び出しの監視とデバッグ
「ツール呼び出しの監視とデバッグ」という見出しのセクションMCP サーバーは stdio 上で通信するため、その標準出力はプロトコルストリームを運び、クリーンに保つ必要があります。サーバーは独自のアプリケーションロギングを構成しません。つまり、主要な可観測性チャネルは、構造化されたツールエラーペイロード、CLI、エンドポイント自身のログです。
- ツールエラーペイロードがシグナルです。 失敗した呼び出しはすべて、
errorを含み、SDK エラーの場合はerror_typeとstatus_codeも含む JSON オブジェクトを返します(エラー処理を参照)。エージェントホストにこれらのペイロードを記録させてください。サーバーに追加の計装を行わなくても、失敗しているツールと正確な原因を特定できます。 - デバッグロギングを有効にし、CLI で再現してください。 MCP サーバー自体はログを出力しませんが、CLI は同じ SDK 呼び出しを実行し、ログを出力します。失敗するツールを、対応する CLI コマンドで
--log-level debugを付けて再現してください。CLI はタイムスタンプ付きで stderr にログを出力し、予期しないエラーについては完全なトレースバックを記録します。これは、デバッガーをアタッチせずにハンドラーの動作を確認する最も直接的な方法です。 - プローブとしてのヘルス。
nextpdf_healthを呼び出して、サーバーがベース URL と API キーを認識していることを確認します。結果はsdk_version、server_url、api_key_configured(ブール値であり、キー自体ではありません)、およびstatusを報告します。 - エンドポイント側の可観測性。 各ツールは 1 つの Connect リクエストにマップされるため、API キーとタイムスタンプを使って、ツールのアクティビティをエンドポイントのアクセスログと関連付けます。他のサービスクライアントで使っているのと同じ認証、クォータ、可観測性の制御下でエンドポイントを実行してください。
よくあるエージェント連携の問題のトラブルシューティング
「よくあるエージェント連携の問題のトラブルシューティング」という見出しのセクション| 症状 | 考えられる原因 | 解決策 |
|---|---|---|
サーバーが ImportError で起動に失敗し、mcp エクストラに言及 | オプション依存関係の mcp が未インストール | pip install nextpdf[mcp] の実行。 |
最初のツール呼び出しの返却値:{"error": "NEXTPDF_BASE_URL environment variable is required..."} | MCP の env ブロックがベース URL を渡していない、またはシェルによる ${NEXTPDF_BASE_URL} の未展開 | エージェントホスト環境での変数設定と、ランチャーによる展開の確認。 |
nextpdf_health が "status": "misconfigured" を報告 | 2 つの必須変数のいずれかが空 | NEXTPDF_BASE_URL と NEXTPDF_API_KEY の両方の指定。 |
パスベースのツールがすべて次を返す:{"error": "PDF file not found: <path>"} | エージェントから、サーバープロセスに見えない相対パスまたはホスト側パスを渡している状態 | サーバーユーザーが読み取れる絶対パスの指定。nextpdf info <path> での確認。 |
ツールが error_typeNextPDFLicenseError(ステータス 402)を返す | この操作に、より高いサーバー側ライセンスティアが必要 | この操作に対する権限を持つエンドポイントとキーの使用。 |
ツールが error_typeAstNoStructTreeError(ステータス 422)を返す | PDF にタグがなく、ヒューリスティックフォールバックがオフ | エンドポイントでのヒューリスティックモード有効化、または事前の PDF タグ付け。 |
ツールが error_typeQuotaExceededError(ステータス 429)を返す | レート制限またはクォータ到達 | 一時停止後の再試行。制限が低すぎる場合はエンドポイントのクォータ引き上げ。 |
ツールが error_typeAstBuildTimeoutError(ステータス 504)、またはトランスポートタイムアウトを返す | ドキュメントが時間予算に対して過大 | max_pages、page_index、または page_start/page_end によるスコープ縮小。 |
| エージェントが NextPDF ツールを 1 つも登録しない | エージェントが python -m nextpdf(CLI)を起動しており、本来必要なのは python -m nextpdf.mcp | python -m nextpdf.mcp を command/args として使用。 |
エンドポイントレベルの障害とデプロイのチェックについては、Connect のトラブルシューティングを参照してください。これらのツールがラップする基盤の SDK 操作については、CLI リファレンスと SDK の概要を参照してください。