跳到內容

Python MCP 伺服器

NextPDF Python SDK 內附一個 Model Context Protocol(MCP)伺服器,會把 PDF 擷取作業以原生 agent 工具的形式對外開放。支援 MCP 的 agent(例如 Claude Code)只要註冊一次伺服器,之後呼叫 NextPDF 工具時,就和呼叫其他任何工具完全相同。

這個伺服器是一層輕量的轉接器。每個工具都會從本機磁碟讀取一份 PDF,對你的 NextPDF Connect endpoint 呼叫非同步用戶端,再以 JSON 字串回傳結果。伺服器本身不含任何商業邏輯,呼叫之間也不會儲存任何資料。

以 MCP extra 安裝 SDK:

Terminal window
pip install nextpdf[mcp]

這個 mcp extra 會加入上游的 mcp 套件(版本限制為 mcp>=1.0,<2.0)。伺服器需要 Python 3.10 或更新版本。

從你的 MCP 用戶端組態啟動這個伺服器模組。下方範例會從主機環境讀取兩個連線值,而不是把祕密直接寫進組態檔(參見 安全性一節):

{
"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 混淆,後者執行的是命令列介面(CLI),不是 MCP 伺服器。

NEXTPDF_BASE_URLNEXTPDF_API_KEY 都是必填。伺服器會等到第一次工具呼叫時,才延遲建立用戶端。若任一變數為空,它會丟出 RuntimeError,並以工具錯誤的形式回傳給 agent,不會讓行程當掉。

伺服器會註冊八個工具。每個工具名稱都帶有 nextpdf_ 前綴。每個工具都對應到非同步用戶端的 ast namespace(命名空間,AsyncNextPDF.ast)上的某個方法,只有下文提到的兩個複合工具例外;它們是在伺服器內部由較低階的呼叫組裝而成。

MCP 工具SDK 呼叫備註
nextpdf_extract_textast.extract_cited_text(pdf_data, page_index=..., headings_only=...)回傳一份 CitedTextBlock 清單。
nextpdf_extract_tablesast.extract_cited_tables(pdf_data, page_range=...)回傳 ExtractCitedTablesResponse
nextpdf_get_astast.get_document_ast(pdf_data, page_range_start=0, page_range_end=..., token_budget=...)回傳 AstDocument
nextpdf_infoast.get_document_ast(pdf_data)伺服器產生一份中繼資料摘要;沒有專屬端點。
nextpdf_health只檢查環境變數;不會發出任何網路呼叫。
nextpdf_searchast.search_ast_nodes(pdf_data, node_type=..., page_index=..., text_query=..., max_results=...)回傳 SearchAstNodesResponse
nextpdf_get_outlineast.search_ast_nodes(pdf_data, node_type="heading", max_results=500)伺服器將標題節點重新整理成大綱。
nextpdf_diffast.get_ast_diff(original_pdf_data, modified_pdf_data)回傳 GetAstDiffResponse

在你串接 agent 之前,請先注意以下工具輸入:

  • 所有路徑輸入(pdf_pathoriginal_pdf_pathmodified_pdf_path)都是執行該伺服器之機器上檔案的絕對路徑。agent 傳入路徑後,伺服器會在本機讀取位元組。沒有上傳工具。
  • nextpdf_extract_text 在輸入結構描述中宣告了一個 max_pages 欄位,但文字處理常式不會把它傳給 SDK。文字的分頁範圍是透過 page_index(單一個以 0 為起始的頁面)控制。當你需要限定整份文件的走訪範圍時,請改用 nextpdf_get_ast 搭配 max_pages
  • nextpdf_get_ast 會把 max_pages 換算成 [0, max_pages - 1] 這個含端點的頁面範圍(max_pages 預設為 50)。傳入 token_budget 以限制回傳樹狀結構的大小。
  • nextpdf_info 會回傳 schema_versionsource_hashpage_countestimated_tokensroot_node_type,以及 root_children_count。這些值來自 AstDocument 模型;其中 estimated_tokens 是一個計算屬性(大約每四個字元算一個 token)。
  • nextpdf_get_outline 會為每個標題回傳一筆項目,內容包含 idpage_indextext,以及 depth(讀自該節點的 attributes["level"],預設為 1),再加上 heading_counttotal_matches,以及 truncated

附帶引用的擷取工具會在每筆結果附加一個 CitationAnchor。每個 anchor 都包含 node_idpage_index、一個正規化後的 bbox(座標範圍為 0.0 到 1.0),以及一個 confidence 信心分數(0.0 到 1.0)。需要 provenance(來源資訊)的 agent 應該呈現這些欄位,而不是只顯示原始文字。

伺服器絕不會讓例外外洩到 agent 傳輸層。call_tool 分派器會攔截每一個錯誤,並以 JSON TextContent 形式回傳;因此一次失敗的工具呼叫會產生一份可供 agent 讀取的結構化酬載,而不是中斷連線。酬載形狀如下:

條件回傳的 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時機
NextPDFLicenseError402license/tier-required該端點對此作業要求更高的伺服器端授權層級。
AstNoStructTreeError422ast/no-struct-tree這份 PDF 未加標記,而伺服器上未啟用啟發式備援。
QuotaExceededError429quota/exceeded達到速率限制或配額。會帶有 retry_after(單位為秒)——前提是伺服器送出了 Retry-After 標頭。
AstBuildTimeoutError504ast/build-timeoutAST 建構超過了伺服器的時間預算。請縮小頁面範圍。
NextPDFAPIError其他 4xx/5xx 錯誤由伺服器提供任何其他 API 層級的失敗。

agent 整合的實務建議:

  • 逾時。 HTTP 用戶端採用固定的預設逾時——總計 60 秒,連線逾時為 10 秒。處理緩慢或龐大的文件時,問題會以下列兩種形式之一浮現:AstBuildTimeoutError(伺服器放棄建構 AST),或者,若是用戶端本身逾時,則是來自傳輸層的 Unexpected error 酬載。當你看到 ast/build-timeout 時,請指示 agent 縮小範圍:調低 max_pages(位於 nextpdf_get_ast 上),或在擷取工具上設定 page_index / page_startpage_end
  • 配額與退避。 碰到 429 時,工具回傳的 error_type 會是 QuotaExceededError,並附上 status_code 429。retry_after 這個值存在於例外物件上。由於伺服器只序列化 errorerror_typestatus_code,agent 應把 429 視為暫停並稍後重試的訊號,而不是從工具輸出剖析某個重試標頭。請在 Connect endpoint 上強制套用配額,而不是在 agent 內處理配額。
  • 未加標記的 PDF。 422 ast/no-struct-tree 代表來源 PDF 沒有結構樹。請在伺服器上為這類文件啟用啟發式模式,或先導向加標記步驟再擷取。

安全性:API 金鑰範圍限定與最小權限

標題為「安全性:API 金鑰範圍限定與最小權限」的區段

請把 API 金鑰當成祕密看待,並以處理資料庫密碼的謹慎程度處理它。

  • 絕不要把金鑰嵌入 MCP 組態檔。 上方的 JSON 範例參照 ${NEXTPDF_API_KEY},因此該值會在啟動時從主機環境或祕密管理器 resolve(解析)而來。組態檔會提交進原始碼控管;祕密則絕不可。
  • 把金鑰範圍限定為唯讀擷取。 MCP 伺服器只會呼叫 AST 擷取面(extract_cited_textextract_cited_tablesget_document_astsearch_ast_nodesget_ast_diff)。它不會執行任何繪製、簽章、塗黑或文件變更。請發給 agent 一把伺服器端範圍僅限於這些唯讀路徑的金鑰;如此一來,即使 agent 遭入侵,也無法觸及寫入或更高層級的作業。
  • 每個 agent 使用專屬金鑰。 為每個 agent 配發專屬金鑰,能讓你撤銷或輪替某個整合而不影響其他整合,也讓端點日誌可歸因到特定 agent。
  • 約束檔案系統。 由於每個工具都會從本機磁碟讀取一個絕對路徑,伺服器可讀取主機行程能讀取的任何檔案。請以非特權使用者執行它、將其工作目錄限制在某個文件資料夾,且絕不要以特權帳號執行它。
  • 優先採用傳輸層安全性(TLS)。 在任何非本機部署中,請把 NEXTPDF_BASE_URL 指向 https:// 端點。SDK 會把金鑰以 Bearer token 形式放在 Authorization 標頭中傳送,因此明文傳輸會在傳輸途中暴露金鑰。

關於支援這些用戶端實務做法的端點側控制措施,請參見 Connect 安全性與維運一節。

在你連接 agent 之前,請先單獨驗證伺服器。最快的檢查不需要 PDF、也不需要網路:

Terminal window
python -c "from nextpdf.mcp import _tool_definitions; print(len(_tool_definitions()))"

正確安裝會印出 8。如果你看到 ImportError,且它提及 mcp extra,表示缺少了該選用相依——請以 pip install nextpdf[mcp] 重新安裝。

接著,透過 CLI 演練這些工具使用的相同 SDK 路徑。CLI 會使用相同的兩個環境變數與你的端點通訊。先設定一次:

Terminal window
export NEXTPDF_BASE_URL="https://connect.example.com"
export NEXTPDF_API_KEY="$(cat /run/secrets/nextpdf_api_key)"

然後確認版本、連線能力,以及執行一次真正的擷取:

Terminal window
nextpdf version
nextpdf info /path/to/sample.pdf
nextpdf extract text /path/to/sample.pdf --headings-only

nextpdf version 不需要憑證即可執行,並會確認套件可正常匯入。nextpdf info 會演練 get_document_ast,也就是 nextpdf_get_astnextpdf_info 背後相同的呼叫。若兩者都成功,代表憑證與端點正確無誤,對應的 MCP 工具也能運作。

若要直接驅動 MCP 協定,請使用上游的 MCP Inspector(隨 mcp 套件一併提供)。把它指向你的 agent 將使用的相同命令與環境,然後手動列出並呼叫工具。確認 nextpdf_health 回報 status: "ok"。只要 NEXTPDF_BASE_URLNEXTPDF_API_KEY 未設定,它就會回傳 misconfigured;這是在 agent 真正呼叫工具之前,最快揪出遺漏環境值的方式。

MCP 伺服器透過 stdio 通訊,因此它的標準輸出承載著協定串流,必須保持乾淨。伺服器不會設定自己的應用程式記錄,這表示你的主要可觀測性管道是結構化的工具錯誤酬載、CLI,以及你端點本身的日誌。

  • 工具錯誤酬載就是訊號。 每一次失敗的呼叫都會回傳一個 JSON 物件,內含 error;對 SDK 錯誤來說,還會有 error_typestatus_code(參見 錯誤處理一節)。請讓 agent 主機記錄這些酬載;無需在伺服器內額外加裝任何檢測,它們就能指出失敗的工具與確切原因。
  • 透過 CLI 搭配除錯記錄重現。 MCP 伺服器本身不發出任何日誌,但 CLI 會演練相同的 SDK 呼叫,而且會記錄。請使用對應的 CLI 命令搭配 --log-level debug 重現失敗的工具。CLI 會將帶時間戳記的記錄寫到 stderr,並為非預期錯誤記錄完整追溯;這是不必掛接除錯器,也能看清某個處理常式行為的最直接方式。
  • 以健康檢查作為探針。 呼叫 nextpdf_health 以確認伺服器看得到一個基底 URL 與一把 API 金鑰。結果會回報 sdk_versionserver_urlapi_key_configured(一個布林值,絕不會回傳金鑰本身),以及 status
  • 端點側的可觀測性。 由於每個工具都對應到一個 Connect 請求,請依 API 金鑰與時間戳記,把工具活動與端點存取日誌相互關聯。請讓端點在與其他服務用戶端相同的驗證、配額與可觀測性控制之下運行。
徵狀可能原因解決方式
伺服器無法啟動,並出現與 mcp extra 有關的 ImportError尚未安裝 mcp 選用相依pip install nextpdf[mcp] 安裝。
第一次工具呼叫回傳 {"error": "NEXTPDF_BASE_URL environment variable is required..."}MCP 的 env 區塊沒有傳入基底 URL,或 shell 沒有展開 ${NEXTPDF_BASE_URL}請在 agent 主機環境中設定該變數,並確認啟動器會展開它。
nextpdf_health 回報 "status": "misconfigured"兩個必填變數其中之一為空請同時提供 NEXTPDF_BASE_URLNEXTPDF_API_KEY
每個以路徑為基礎的工具都回傳 {"error": "PDF file not found: <path>"}agent 傳入了伺服器行程看不到的相對路徑或主機端路徑請傳入伺服器使用者可讀的絕對路徑,並以 nextpdf info <path> 確認。
工具回傳 error_typeNextPDFLicenseError(狀態 402)此作業需要更高的伺服器端授權層級請使用一個有權執行此作業的端點與金鑰。
工具回傳 error_typeAstNoStructTreeError(狀態 422)這份 PDF 未加標記,而啟發式備援為關閉請在端點上啟用啟發式模式,或先為這份 PDF 加標記。
工具回傳 error_typeQuotaExceededError(狀態 429)碰到了速率限制或配額請暫停並重試;若上限過低,請提高端點配額。
工具回傳 error_typeAstBuildTimeoutError(狀態 504),或一個傳輸逾時這份文件超出時間預算請以 max_pagespage_index,或 page_start/page_end 縮小範圍。
agent 沒有註冊任何 NextPDF 工具agent 呼叫了 python -m nextpdf(CLI),而不是 python -m nextpdf.mcp請把 python -m nextpdf.mcp 用作 command/args

關於端點層級的失敗與部署檢查,請參見 Connect 排解問題一節。關於這些工具所封裝的底層 SDK 作業,請參見 CLI 參考SDK 概觀