跳转到内容

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,并把 server 密钥、server 证书与客户端证书颁发机构以部署 secret 的方式提供。
  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 会重播已缓存的结果。
  • 路径包覆测试会断言:解析后落在基底目录之外的文档输出路径会被拒绝。
  • 请让测试 fixture 保持小且不含敏感数据;绝不要提交真实的 API 密钥或文档内容。
  • API 参考 —— 精确的工具、RPC 与消息符号
  • 工具目录 —— 已验证的 core 工具集与运行时计数
  • HITL 风险 tier —— 风险模型与确认封套
  • 组态 —— 解析顺序与仅能升级的覆盖
  • 部署 —— RoadRunner 配置文件、Redis 与双向 TLS
  • 安全与维运 —— 验证、传输层安全与威胁模型