Перейти к содержимому

Руководство разработчика NextPDF Connect

NextPDF Connect (nextpdf/server) предоставляет независимый от фреймворка движок NextPDF PDF 2.0 как сервис. Он не реализует генерацию PDF заново, а представляет каждую возможность движка как именованный инструмент со схемой и обслуживает этот каталог по трём транспортам: Model Context Protocol (MCP) через стандартный ввод и вывод, Representational State Transfer (REST) Application Programming Interface (API) и gRPC. Используйте это руководство, когда разрабатываете для сервера, расширяете его набор инструментов или запускаете его в продакшене.

Дизайн строится на трёх концепциях: реестре инструментов, трёх независимых транспортах и шлюзе подтверждения с участием человека (human-in-the-loop, HITL). На этой странице объясняется, как они сочетаются и как работать с ними, не ослабляя модель безопасности. Точные символы инструментов, удалённых вызовов процедур (RPC) и сообщений см. в разделе Справочник API.

Предварительные требования: PHP 8.4, Composer 2 и — для сетевых транспортов — бинарный файл RoadRunner и хотя бы один ключ API. Установите командой composer require nextpdf/server.

Держите каждую обязанность по правильную сторону границы. Инструмент — это тонкая обёртка вокруг вызова движка; в нём не должно быть интерпретации макета, семантики документа или логики преобразования.

СлойВладелецОбязанностьНе размещайте здесь
Клиент или агентВаша интеграцияВыбор инструмента для вызова; передача запросов на подтверждение человеку.Логика движка или определение уровня.
Транспортnextpdf/serverОформление запросов как JSON-RPC, HTTP или Protocol Buffers; аутентификация; маршрутизация к исполнителю инструментов.Семантика документа.
Реестр инструментовnextpdf/serverОбнаружение уровней, регистрация инструментов с учётом списка разрешённых для безопасности, поиск инструмента по имени.Генерация PDF.
Инструментnextpdf/serverПроверка аргументов по входной схеме и вызов движка.Интерпретация макета или многошаговая оркестрация.
Шлюз подтвержденияnextpdf/serverУдержание операции ApprovalRequired, пока её не одобрит человек.Аутентификация вызывающей стороны.
Движокnextpdf/corenextpdf/premium)Генерация, инспектирование и преобразование содержимого PDF.Вопросы транспорта или аутентификации.

У каждого транспорта есть собственная точка входа и фабрика загрузки. Каждый транспорт явно конструирует свой граф объектов. Контейнер внедрения зависимостей при регистрации не используется.

  1. Загрузка конфигурации. Сервер MCP разрешает конфигурацию сначала из переменных окружения (NEXTPDF_MCP_*), затем из секции nextpdf_mcp YAML-файла, затем из встроенных значений по умолчанию и формирует readonlyMcpConfig. Серверы REST и gRPC читают HttpConfig из переменных окружения NEXTPDF_*. См. Конфигурация.
  2. Построение политики безопасности. Список разрешённых enabled_tools строится до реестра, поэтому он ограничивает обнаружение начиная с самой первой регистрации.
  3. Конструирование реестра и обнаружение инструментов. ToolRegistry::registerDefaults() регистрирует уровень core, затем провайдеры Pro и Enterprise, когда их классы разрешаются, а затем встроенные провайдеры AST и мутаций с учётом их условий окружения.
  4. Построение общих хранилищ и шлюза. Хранилище документов в памяти строится на основе настроенных TTL и ёмкости; ConfirmationGate собирается со своим хранилищем одноразовых токенов.
  5. Привязка транспорта. MCP входит в цикл «чтение — обработка — запись» через stdio до конца файла. REST и gRPC строят свою таблицу маршрутов или сервисов из обнаруженных уровней, а затем передают цикл обработки запросов RoadRunner.

Далее запрос проходит такой путь: аутентификация (REST и gRPC), разрешение инструмента или операции, прохождение шлюза подтверждения для работы ApprovalRequired, выполнение на движке и возврат результата. См. Загрузка и обнаружение.

Три транспорта используют общие концепции реестра, конфигурации и шлюза, но выполняются как независимые процессы. Запуск одного транспорта не запускает остальные.

ТранспортТочка входаКогда его выбирать
MCPbin/nextpdf-mcpЛокальный клиент искусственного интеллекта (ИИ), запускающий сервер как доверенный подпроцесс.
RESTbin/nextpdf-serverСетевые HTTP-клиенты; описывается документом OpenAPI 3.1.
gRPCbin/nextpdf-grpcТипизированные потоковые клиенты; сервис nextpdf.connect.v1.NextPDFConnect.

Выбирайте транспорты по профилю RoadRunner, который запускаете: .rr.yaml (только REST), .rr.grpc.yaml (только gRPC) или .rr.full.yaml (оба). Транспорт MCP — обычный подпроцесс, ему не нужен супервизор. Подробности обмена данными см. в разделах Транспорт MCP, Транспорт REST и Транспорт gRPC.

Запускайте сетевые транспорты под RoadRunner с общими хранилищами и ключами, смонтированными как секреты. Объединённый профиль позволяет REST и gRPC работать под общим супервизором.

Путь или параметрНазначение
.rr.full.yamlОбъединённый профиль REST и gRPC под единым супервизором.
NEXTPDF_API_KEYS_FILEПуть к файлу ключей API, смонтированному как секрет и перезагружаемому на лету.
NEXTPDF_REDIS_HOSTВключает хранилища ограничения частоты, идемпотентности и документов на основе Redis для пулов с несколькими воркерами.
NEXTPDF_WORKER_COUNT / NEXTPDF_GRPC_WORKER_COUNTРазмер пула воркеров для пулов HTTP и gRPC.
Базовый каталог выводаВыделенный том с минимально необходимыми правами файловой системы для инструментов файлового вывода.

Следующий пример командной оболочки загружает объединённый профиль с ключами, смонтированными как секреты, и общим хранилищем Redis. В нём нет секретов; ключи монтируются по пути /run/secrets/api-keys.

Окно терминала
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

Для пула с несколькими воркерами настройте Redis и убедитесь, что ext-redis есть в запущенном образе. Без него хранилища ограничения частоты, идемпотентности и документов работают отдельно в каждом воркере. См. развёртывание.

Реестр инструментов и определение уровня

Заголовок раздела «Реестр инструментов и определение уровня»

NextPDF\Server\ToolRegistry (src/ToolRegistry.php) строит каталог при загрузке. Уровень — объявленный инвариант: каждый инструмент возвращает собственные tier() и riskLevel(). Реестр никогда не выводит уровень из пространства имён или пакета.

  1. Уровень core регистрируется безусловно: инструменты документов и диагностики, плюс generate_barcode, когда присутствует основной реестр кодировщиков штрихкодов, плюс parse_pdf только тогда, когда NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLED равно true или 1.
  2. Провайдеры Pro и Enterprise регистрируются, когда разрешаются их классы провайдеров; это проверяется через class_exists(). Отсутствующий уровень пропускается без сообщений.
  3. Встроенные провайдеры AST и мутаций регистрируются под уровнем Pro и управляются через NEXTPDF_AST_TOOLS_ENABLED и NEXTPDF_MUTATION_TOOLS_ENABLED (оба включены по умолчанию).
  4. Фильтр политики безопасности пересекает каждую регистрацию со списком разрешённых enabled_tools. Список разрешённых только вычитает; он никогда ничего не добавляет. Счётчик по уровням учитывает только инструменты, которые допускает политика.

Ответ MCP initialize и конечная точка REST GET /api/v1/capabilities сообщают итоговые счётчики по уровням и общее число. Считайте любое фиксированное итоговое число в тексте устаревшим; запрашивайте его у работающего сервера. См. Каталог инструментов.

Каждый инструмент объявляет один из четырёх уровней риска из перечисления RiskLevel (src/Config/RiskLevel.php): Safe (0), Caution (1), Review (2) и ApprovalRequired (3). Аудит-логирование применяется на уровне Caution и выше. Переопределение конфигурации может повысить риск инструмента, но никогда не может понизить риск инструмента, который по замыслу относится к ApprovalRequired. Загрузчик конфигурации выбрасывает исключение во время загрузки, и сервер отказывается запускаться, вместо того чтобы работать с ослабленным шлюзом.

Когда инструмент ApprovalRequired вызывается без действительного токена, ConfirmationGate (src/Mcp/ConfirmationGate.php) возвращает одноразовый токен-запрос. Токен связывает имя инструмента, случайный nonce и время жизни (TTL) в 300 секунд, но не аргументы, потому что при повторе клиенты могут заново сериализовать аргументы с другим порядком ключей. Агент передаёт запрос человеку и повторно вызывает тот же инструмент с токеном в аргументе _confirmation_token. При использовании токен расходуется и разрешает ровно один защищённый шлюзом вызов.

Следующий пример на PHP — вспомогательная функция, не зависящая от транспорта. Она выполняет вызов инструмента MCP и при запросе подтверждения показывает запрос человеку, который принимает решение, прежде чем повторить вызов с выданным токеном. Она объявляет строгие типы, полностью снабжена подсказками типов и перехватывает наиболее конкретное исключение, а не подавляет все ошибки.

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);
}
}

Подключите McpClientInterface, HumanApproverInterface и ApprovalDeniedException к своему транспорту и каналу утверждения. Повторный вызов использует исходные аргументы плюс выданный токен; никогда не подтверждайте запрос автоматически без решения человека. См. Уровни риска HITL.

Расширяйте сервер через добавление инструментов и предоставление провайдеров, а не через редактирование реестра.

Точка расширенияДля чего использоватьОграничение
Класс, реализующий ToolInterfaceНовая возможность движка, представленная как инструмент.Объявите tier(), riskLevel(), category() и схему JSON Schema inputSchema(); оставляйте класс тонкой обёрткой движка.
Провайдер, реализующий ToolProviderInterfaceРегистрация набора инструментов для уровня.Провайдеры Pro и Enterprise обнаруживаются через class_exists(); не требуйте проприетарный пакет со стороны сервера.
enabled_tools — список разрешённыхОграничение области каталога по принципу минимальных привилегий.Список разрешённых только вычитает; он не может зарегистрировать отсутствующий инструмент.
risk_level_overridesУсиление защиты развёртывания за счёт повышения риска инструмента.Только повышение; понижение инструмента ApprovalRequired приводит к сбою загрузки.
Внедряемые точки сопряжения транспорта и воркеровТестирование сервера в изоляции.Эти границы существуют для тестов, а не для подключения приложения.
  1. Выберите профиль. Запустите .rr.yaml, .rr.grpc.yaml или .rr.full.yaml для тех транспортов, которые вы предоставляете.
  2. Смонтируйте ключи из секрета. Укажите в NEXTPDF_API_KEYS_FILE файл секрета; предпочтите файловое хранилище ключей с перезагрузкой на лету, чтобы ротация не требовала перезапуска.
  3. Настройте общие хранилища. Установите NEXTPDF_REDIS_HOST и убедитесь в наличии ext-redis для любого пула размером более одного воркера; разместите хранилище задач SQLite на томе, доступном для записи всем воркерам.
  4. Завершайте TLS. Запускайте REST за терминатором Transport Layer Security (TLS); запускайте gRPC со взаимным TLS в любой недоверенной сети, передавая ключ сервера, сертификат сервера и центр сертификации клиентов как секреты развёртывания.
  5. Проверяйте работоспособность. Используйте анонимные конечные точки /healthz и /readyz (REST) или RPC HealthCheck и ReadinessCheck (gRPC) для проб оркестратора.
  6. Ограничьте область каталога. Ограничьте enabled_tools минимальным набором, который нужен интеграции.

Проверяйте работоспособность Redis, а не считайте её гарантированной. Сервер REST переходит на хранилища в памяти, когда настроенное соединение с Redis не удаётся установить. См. развёртывание и Безопасность и эксплуатация.

СбойГде проявляетсяРекомендуемая реакция
Неизвестный document_idВыполнение инструментаВерните вызывающей стороне конкретную ошибку; укажите ей сначала вызвать create_pdf.
Устаревший ETag при мутацииИнструмент мутации ASTПеречитайте документ с помощью get_document_ast и повторите попытку со свежим ETag.
Отсутствующий или недействительный ключ API (REST)Промежуточное ПО аутентификацииВерните 401 с запросом WWW-Authenticate: Bearer; не раскрывайте, какая именно часть была неверной.
Нет права на уровень (REST)АвторизацияВерните 403; уровень ключа ниже уровня операции.
Маршрут уровня отсутствует (REST)МаршрутизаторВерните 404; пакет не установлен. Это ожидаемая операция, а не ошибка.
Неверный токен (gRPC)Аутентификатор gRPCЗавершите вызов с ошибкой UNAUTHENTICATED.
Redis недоступенЗагрузка или выполнениеПереходите на хранилища в памяти; оповестите операторов и проверьте работоспособность Redis.
Путь вывода за пределами базового каталогаИнструмент вывода в файлыОткажите по умолчанию; путь нормализуется, и обход каталогов отклоняется.

Представляйте сбои движка как конкретные объекты ошибок, а не как тихие успехи. Справочник API подробно описывает модель ошибок для каждого транспорта.

АспектПо умолчаниюКогда переопределять
parse_pdfОтключено (включается через NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLED).Включайте только тогда, когда интеграции нужно структурное инспектирование.
enabled_toolsПусто (разрешены все обнаруженные инструменты).Задайте явный список разрешённых для развёртываний с минимальными привилегиями.
Переопределения рискаНет.Повышайте риск для усиленного развёртывания; никогда не пытайтесь его понизить.
document_ttl / max_documents1800 секунд / 50 документов.Снижайте для развёртываний, чувствительных к месту хранения данных, или с ограничением памяти.
allow_file_outputВключено.Установите false для развёртываний без состояния, чувствительных к месту хранения данных.
Число воркеровЧетыре (HTTP), два (gRPC).Подбирайте с учётом наблюдаемой задержки и доступных ядер.
Слушатель RESTОткрытый HTTP за терминатором TLS.Всегда завершайте TLS на вышестоящем узле; никогда не открывайте незашифрованный трафик в недоверенной сети.
gRPC в недоверенных сетяхВзаимный TLS.Обязательно; никогда не запускайте незашифрованный слушатель gRPC в недоверенной сети.
  • Тесты реестра подтверждают, что отсутствующий уровень Pro или Enterprise пропускается без сообщений, а основной каталог всё равно регистрируется.
  • Тесты списка разрешённых подтверждают, что enabled_tools вычитает и никогда не добавляет инструмент, который реестр не обнаружил.
  • Тесты шлюза подтверждения проверяют, что инструмент ApprovalRequired возвращает запрос при первом вызове, выполняется один раз по действительному одноразовому токену и аннулирует токен по истечении его TTL.
  • Тесты понижения подтверждают, что запись risk_level_overrides, ослабляющая инструмент ApprovalRequired, приводит к сбою загрузки.
  • Тесты аутентификации охватывают отсутствующие, некорректные, отключённые и просроченные ключи в REST (401 с WWW-Authenticate) и gRPC (UNAUTHENTICATED), а также отклонение по праву на уровень (403).
  • Тесты параллелизма подтверждают, что устаревший ETag приводит к сбою мутации, а повторный idempotency_key воспроизводит кэшированный результат.
  • Тесты ограничения по пути подтверждают, что путь вывода в файл, разрешающийся за пределы базового каталога, отклоняется.
  • Держите фикстуры небольшими и нечувствительными; никогда не фиксируйте в системе контроля версий настоящий ключ API или содержимое документа.