跳到內容

NextPDF Connect 開發者指南

NextPDF Connect(nextpdf/server)將不依賴 Framework(框架)的 NextPDF PDF 2.0 引擎包裝成一項服務。它不會重新實作 PDF 產生流程,而是以具名且附 schema 描述的工具形式公開每一項引擎能力,並透過三種傳輸層提供完整工具目錄:透過標準輸入輸出的 Model Context Protocol(MCP)、一套 Representational State Transfer(REST)應用程式介面(API),以及 gRPC。當你要以這台 server 為基礎開發、擴充其工具集,或在正式環境維運它時,請參閱本指南。

整體設計建立在三個概念上:工具登錄(registry)、三個彼此獨立的傳輸層,以及人為介入(HITL)確認 gate。本頁說明它們如何彼此搭配,以及如何在不削弱安全模型的前提下使用。若需要精確的工具、RPC 與訊息符號,請閱讀 API 參考

先決條件為 PHP 8.4、Composer 2;若要使用網路傳輸層,還需要 RoadRunner 執行檔與至少一組 API 金鑰。請以 composer require nextpdf/server 安裝。

請確保各項職責留在所屬邊界內。工具只是引擎呼叫的一層薄包裝;它不得承載版面詮釋、文件語意或轉換邏輯。

層級負責方職責不可放在這裡
用戶端或 AI Agent(代理)你的整合程式決定要呼叫哪個工具;將確認挑戰轉達給人。引擎邏輯或 tier 偵測。
傳輸層nextpdf/server封裝請求(JSON-RPC、HTTP 或 Protocol Buffers)、進行驗證,並將請求路由至工具執行器。文件語意。
工具登錄(registry)nextpdf/server探索各 tier,在安全允許清單限制下登錄工具,並依名稱查找工具。PDF 產生。
工具nextpdf/server依輸入 schema 驗證引數,並呼叫引擎。版面詮釋或多步驟編排。
確認 gatenextpdf/server暫扣一項 ApprovalRequired 作業,直到有人授權為止。呼叫端驗證。
引擎nextpdf/core(以及 nextpdf/premium產生、檢視與轉換 PDF 內容。傳輸層或驗證事務。

每個傳輸層都有各自的進入點與啟動工廠(factory),並明確建構自己的物件圖。不需要註冊依賴注入容器。

  1. 載入組態。 MCP server 會 resolve(解析)組態,優先順序為:環境變數(NEXTPDF_MCP_*)高於 YAML 檔的 nextpdf_mcp 區段,再高於內建預設值,最後產出一份 readonlyMcpConfig。REST 與 gRPC server 則讀取 HttpConfig,來源是 NEXTPDF_* 環境變數。請參閱 組態
  2. 建立安全政策。 enabled_tools 允許清單會先於 registry 建立,因此從第一次登錄起就能約束探索範圍。
  3. 建構 registry 並探索工具。 ToolRegistry::registerDefaults() 會先登錄 core tier,接著在 Pro 與 Enterprise 供應器類別可解析時登錄它們,最後在環境 gate 允許時登錄隨附的 AST 與突變供應器。
  4. 建立共用儲存與 gate。 記憶體內文件儲存會依設定的 TTL 與容量建立;ConfirmationGate 則連同其單次使用權杖儲存一併組裝起來。
  5. 綁定傳輸層。 MCP 會透過 stdio 進入「讀取—處理—寫出」迴圈,直到讀到檔案結尾為止。REST 與 gRPC 則依偵測到的各 tier 建立路由或服務表,並把請求迴圈交給 RoadRunner。

接著,單次請求的流向為:驗證(REST 與 gRPC)、解析工具或作業、對 ApprovalRequired 工作執行確認 gate、對引擎執行,最後回傳結果。請參閱 啟動與探索

這三個傳輸層在概念上共用 registry、組態與 gate,但各自是獨立行程。啟動其中一個,不會連帶啟動其他傳輸層。

傳輸層進入點何時選用它
MCPbin/nextpdf-mcp會以可信任子行程啟動 server 的本機 AI 用戶端。
RESTbin/nextpdf-server網路型 HTTP 用戶端;由一份 OpenAPI 3.1 文件描述。
gRPCbin/nextpdf-grpc型別化的串流(stream)用戶端;對應 nextpdf.connect.v1.NextPDFConnect 服務。

請依執行的 RoadRunner 設定檔選擇傳輸層:.rr.yaml(僅 REST)、.rr.grpc.yaml(僅 gRPC),或 .rr.full.yaml(兩者皆有)。MCP 傳輸層只是一個一般子行程,不需要監管程序。各傳輸層的傳輸協定細節分別記載於 MCP 傳輸層REST 傳輸層,以及 gRPC 傳輸層

請讓網路傳輸層在 RoadRunner 之下執行,搭配共用儲存與以 secret 掛載的金鑰。合併設定檔可讓 REST 與 gRPC 共用同一個監管程序。

路徑或設定用途
.rr.full.yaml讓 REST 與 gRPC 在同一個監管程序下執行的合併設定檔。
NEXTPDF_API_KEYS_FILE指向以 secret 掛載且可熱重載的 API 金鑰檔路徑。
NEXTPDF_REDIS_HOST為多 worker 池啟用以 Redis 為後端的速率限制、冪等性與文件儲存。
NEXTPDF_WORKER_COUNT / NEXTPDF_GRPC_WORKER_COUNTHTTP 與 gRPC worker 池的規模設定。
輸出基底目錄供檔案輸出工具使用的專用磁碟區,採用最小權限的檔案系統權限。

以下 shell 範例會使用以 secret 掛載的金鑰與共用 Redis 儲存,啟動合併設定檔。檔案本身不含任何 secret;金鑰掛載於 /run/secrets/api-keys

Terminal window
export NEXTPDF_API_KEYS_FILE=/run/secrets/api-keys
export NEXTPDF_WORKER_COUNT=8
export NEXTPDF_GRPC_WORKER_COUNT=4
export NEXTPDF_REDIS_HOST=redis
./vendor/bin/rr serve -c .rr.full.yaml

若要使用多 worker 池,請設定 Redis,並確認執行中的映像檔包含 ext-redis;缺少它時,速率限制、冪等性與文件儲存都會變成各 worker 各自獨立。請參閱 部署

NextPDF\Server\ToolRegistrysrc/ToolRegistry.php)會在啟動時建立工具目錄。tier 是一項宣告式不變量:每個工具回傳自己的 tier()riskLevel();registry 絕不從命名空間或封裝方式推斷 tier。

  1. Core tier 會無條件登錄:文件與診斷工具,外加 core 條碼編碼器登錄存在時才加入的 generate_barcode,以及 parse_pdf——但僅在 NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLEDtrue1 時才登錄。
  2. Pro 與 Enterprise 供應器 會在其供應器類別可解析時登錄,並透過 class_exists() 探測。不存在的 tier 會被靜默略過。
  3. 隨附的 AST 與突變供應器 會登錄在 Pro tier 之下,並由 NEXTPDF_AST_TOOLS_ENABLEDNEXTPDF_MUTATION_TOOLS_ENABLED 控管(兩者預設皆為啟用)。
  4. 安全政策篩選器 會將每一次登錄與 enabled_tools 允許清單取交集。允許清單只會做減法,絕不會增加工具。各 tier 的計數只計入政策放行的工具。

由此產生的各 tier 計數與總數,會回報於 MCP 的 initialize 回應與 REST 的 GET /api/v1/capabilities 端點中。文件中任何固定的總數都應視為過時;請以查詢執行中的 server 為準。請參閱 工具目錄

每個工具都從 RiskLevel 列舉(src/Config/RiskLevel.php)宣告四種風險等級之一:Safe(0)、Caution(1)、Review(2)與 ApprovalRequired(3)。稽核記錄會套用於 Caution 以上的等級。組態覆寫可以提高工具的風險,但它絕不能調降一個依設計屬於 ApprovalRequired 的工具。組態載入器會在載入時拋出例外,server 會拒絕啟動,而不是帶著被削弱的 gate 執行。

當一個 ApprovalRequired 工具在沒有有效權杖的情況下被呼叫時,ConfirmationGatesrc/Mcp/ConfirmationGate.php)會回傳一個單次使用的挑戰權杖。權杖綁定的是工具名稱、一個隨機 nonce,以及 300 秒的存活時間(TTL)——但不綁定引數,因為用戶端在重試時可能以不同的鍵排序重新序列化引數。代理(agent)會把挑戰轉達給人,再以 _confirmation_token 引數帶著該權杖重新呼叫同一個工具。權杖一經使用即被消耗,恰好放行一次受 gate 管制的呼叫。

以下 PHP 範例是一個與傳輸層無關的輔助程式;它會驅動一次 MCP 工具呼叫,並在遇到確認挑戰時,先把挑戰呈現給人為核可者,再以核發的權杖重試。它宣告 strict types、完整標註型別,且只攔截最具體的例外,而不是吞掉每個錯誤。

examples/connect/confirm-and-call.php
<?php
declare(strict_types=1);
namespace App\Connect;
use JsonException;
/**
* Drives one tool call and resolves an ApprovalRequired confirmation
* challenge through a human approver before retrying.
*/
final readonly class ConfirmingToolCaller
{
public function __construct(
private McpClientInterface $client,
private HumanApproverInterface $approver,
) {}
/**
* @param non-empty-string $toolName
* @param array<string, mixed> $arguments
*
* @return array<string, mixed> The tool result content
*
* @throws JsonException When a response cannot be decoded
* @throws ApprovalDeniedException When the human declines the challenge
*/
public function call(string $toolName, array $arguments): array
{
$response = $this->client->callTool($toolName, $arguments);
if (!isset($response['challenge'], $response['token'])) {
return $response;
}
$challenge = (string) $response['challenge'];
$token = (string) $response['token'];
if (!$this->approver->approve($toolName, $challenge)) {
throw new ApprovalDeniedException($toolName);
}
$arguments['_confirmation_token'] = $token;
return $this->client->callTool($toolName, $arguments);
}
}

請將 McpClientInterfaceHumanApproverInterfaceApprovalDeniedException 接到你自己的傳輸層與核可管道。重試會沿用原本的引數,並加上核發的權杖;絕不要在沒有人為裁決的情況下自動核可一項挑戰。請參閱 HITL 風險 tier

要擴充這台 server,應新增工具並提供供應器,而不是編輯 registry。

擴充點用於限制
一個類別,實作 ToolInterface以工具形式公開的一項新引擎能力。宣告 tier()riskLevel()category(),以及一份 JSON Schema 的 inputSchema();並讓它維持為一層薄的引擎包裝。
一個 ToolProviderInterface 供應器為某個 tier 登錄一組工具。Pro 與 Enterprise 供應器是透過 class_exists() 探索;不要讓 server 依賴該專有套件。
enabled_tools 允許清單以最小權限縮限對外公開的工具目錄。允許清單只做減法;它無法登錄一個不存在的工具。
risk_level_overrides透過提高工具風險來強化部署的安全性。僅能升級;調降一個 ApprovalRequired 工具會導致啟動失敗。
可注入的傳輸層與 worker seam在隔離環境下測試 server。這些 seam 是為測試而存在,不是供應用程式接線使用。
  1. 選擇一個設定檔。 依你要公開的傳輸層,執行 .rr.yaml.rr.grpc.yaml.rr.full.yaml
  2. 從 secret 掛載金鑰。NEXTPDF_API_KEYS_FILE 指向一個 secret 檔;建議使用可熱重載的檔案金鑰儲存,如此輪替金鑰時就不需重啟。
  3. 設定共用儲存。 設定 NEXTPDF_REDIS_HOST,並確認任何超過一個 worker 的池都有 ext-redis;把 SQLite 工作儲存放在所有 worker 都能寫入的磁碟區上。
  4. 終結 TLS。 讓 REST 在一個傳輸層安全(TLS)終結器後方執行;在任何不受信任的網路上以雙向 TLS 執行 gRPC,並以部署 secret 提供 server 金鑰、server 憑證與用戶端憑證授權單位。
  5. 探測健康狀態。 使用匿名的 /healthz/readyz 端點(REST),或 HealthCheckReadinessCheck RPC(gRPC),供編排器探測使用。
  6. 縮限工具目錄。enabled_tools 限制為某個整合真正需要的最小工具集。

請驗證 Redis 的健康狀態,不要想當然耳:當設定的 Redis 連線失敗時,REST server 會退回使用記憶體內儲存。請參閱 部署安全與維運

失敗出現位置建議的回應
未知的 document_id工具執行回傳一個已定義的錯誤給呼叫端;指示它先呼叫 create_pdf
變更時 ETag 過時AST 突變工具get_document_ast 重新讀取文件,再以新的 ETag 重試。
API 金鑰遺失或無效(REST)驗證 middleware回傳 401 並附帶 WWW-Authenticate: Bearer 挑戰;不要洩漏具體是哪一部分出錯。
tier 未獲授權(REST)授權回傳 403;該金鑰的 tier 低於該作業的 tier。
tier 路由不存在(REST)路由器回傳 404;該套件未安裝。這是預期內的行為,並非故障。
權杖錯誤(gRPC)gRPC 驗證器讓該呼叫以 UNAUTHENTICATED 失敗。
無法連到 Redis啟動期或執行期降級為記憶體內儲存;通知維運人員並驗證 Redis 的健康狀態。
輸出路徑落在基底目錄之外檔案輸出工具以失敗為安全預設(fail closed)處理;路徑會被正規化,且穿越路徑會被拒絕。

請將引擎失敗呈現為已定義的錯誤物件,絕不要呈現為無聲的成功。各傳輸層的錯誤模型詳載於 API 參考

事項預設值何時應覆寫
parse_pdf停用(透過 NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLED 選擇啟用)。只有在某個整合需要結構性檢視時才啟用。
enabled_tools空白(允許所有已探索到的工具)。為最小權限部署設定一份明確的允許清單。
風險覆寫無。對強化過的部署提高風險;絕不要嘗試調降。
document_ttl / max_documents1800 秒 / 50 份文件。對於資料落地敏感或記憶體受限的部署,請調低。
allow_file_output啟用。對於無狀態、資料落地敏感的部署,請設為 false
worker 數量四(HTTP)、二(gRPC)。依觀察到的延遲與可用核心數調整規模。
REST 監聽器在 TLS 終結器後方的純文字 HTTP。請一律在上游終結 TLS;絕不要在不受信任的網路上公開純文字。
在不受信任網路上的 gRPC雙向 TLS。這是必要條件;絕不要在不受信任的網路上執行純文字 gRPC 監聽器。
  • Registry 測試會斷言:當 Pro 或 Enterprise tier 不存在時,會被靜默略過,而 core 工具目錄仍會登錄。
  • 允許清單測試會斷言:enabled_tools 只做減法,絕不會加入一個 registry 未曾探索到的工具。
  • 確認 gate 測試會斷言:一個 ApprovalRequired 工具在首次呼叫時回傳挑戰、在持有有效的單次使用權杖時執行一次,且該權杖會在其 TTL 之後過期。
  • 調降測試會斷言:一個 risk_level_overrides 項目若削弱了 ApprovalRequired 工具,會導致啟動失敗。
  • 驗證測試會涵蓋 REST 上金鑰遺失、格式錯誤、已停用與已過期的情況(401 加上 WWW-Authenticate)與 gRPC(UNAUTHENTICATED),以及 tier 授權遭拒(403)。
  • 並行測試會斷言:過時的 ETag 會讓變更失敗,而重複的 idempotency_key 會重播已快取的結果。
  • 路徑包覆測試會斷言:解析後落在基底目錄之外的檔案輸出路徑會被拒絕。
  • 請讓測試夾具維持精簡且不含敏感資料;絕不要提交真實的 API 金鑰或文件內容。
  • API 參考 —— 精確的工具、RPC 與訊息符號
  • 工具目錄 —— 已驗證的 core 工具集與執行期計數
  • HITL 風險 tier —— 風險模型與確認封套
  • 組態 —— 解析順序與僅能升級的覆寫
  • 部署 —— RoadRunner 設定檔、Redis 與雙向 TLS
  • 安全與維運 —— 驗證、傳輸層安全與威脅模型