Salta ai contenuti

NextPDF Connect: guida per sviluppatori

NextPDF Connect (nextpdf/server) incapsula in un servizio indipendente dal framework il motore PDF 2.0 di NextPDF. Non reimplementa la generazione di PDF. Espone ogni funzionalità del motore come strumento con nome e schema descrittivo e pubblica il catalogo su tre trasporti: Model Context Protocol (MCP) su standard input e output, un’API (Application Programming Interface) REST (Representational State Transfer) e gRPC. Usare questa guida quando si lavora sul server, se ne estende l’insieme di strumenti o lo si gestisce in produzione.

L’intero progetto si fonda su tre concetti: il registro degli strumenti, i tre trasporti indipendenti e il gate di conferma con intervento umano (human-in-the-loop, HITL). Questa pagina spiega come questi elementi si integrano tra loro e come utilizzarli senza indebolire il modello di sicurezza. Per i simboli esatti di strumenti, RPC e messaggi, consultare la documentazione di riferimento dell’API.

Prerequisiti: PHP 8.4, Composer 2 e, per i trasporti di rete, il binario RoadRunner e almeno una chiave API. Installare con composer require nextpdf/server.

Mantenere ogni responsabilità dal lato corretto del rispettivo confine. Uno strumento è un wrapper sottile attorno a una chiamata al motore; non deve contenere interpretazione dell’impaginazione, semantica del documento o logica di trasformazione.

LivelloDi competenza diResponsabilitàNon collocare qui
Client o agenteLa propria integrazioneDecidere quale strumento chiamare; inoltrare a una persona le richieste di conferma.Logica del motore o rilevamento dei livelli.
Trasportonextpdf/serverGestire il framing delle richieste (JSON-RPC, HTTP o Protocol Buffers), autenticare e instradare verso l’esecutore degli strumenti.Semantica del documento.
Registro degli strumentinextpdf/serverRilevare i livelli, registrare gli strumenti nel rispetto dell’allowlist di sicurezza, risolvere uno strumento per nome.Generazione di PDF.
Strumentonextpdf/serverConvalidare gli argomenti rispetto allo schema di input e chiamare il motore.Interpretazione dell’impaginazione o orchestrazione in più fasi.
Gate di confermanextpdf/serverMantenere in sospeso un’operazione ApprovalRequired finché una persona non la autorizza.Autenticazione del chiamante.
Motorenextpdf/core (e nextpdf/premium)Generare, ispezionare e trasformare il contenuto dei PDF.Aspetti di trasporto o autenticazione.

Ogni trasporto ha un punto di ingresso e una factory di avvio propri, e ciascuno costruisce esplicitamente il proprio grafo di oggetti. Non esiste alcun container di dependency injection da configurare.

  1. Caricare la configurazione. Il server MCP risolve la configurazione dando precedenza alle variabili d’ambiente (NEXTPDF_MCP_*) sulla sezione nextpdf_mcp del file YAML, e a quest’ultima sui valori predefiniti incorporati; il risultato è un readonlyMcpConfig. I server REST e gRPC leggono HttpConfig dalle variabili d’ambiente NEXTPDF_*. Vedere Configurazione.
  2. Costruire i criteri di sicurezza. L’allowlist enabled_tools viene costruita prima del registro, così da vincolare l’individuazione già dalla prima registrazione.
  3. Costruire il registro e individuare gli strumenti. ToolRegistry::registerDefaults() registra il livello core, poi i provider Pro ed Enterprise quando le loro classi vengono risolte e infine i provider AST e di mutation in bundle, in base ai rispettivi gate d’ambiente.
  4. Costruire gli store condivisi e il gate. Lo store dei documenti in memoria viene costruito a partire da TTL e capacità configurati; il ConfirmationGate viene assemblato con il proprio store di token monouso.
  5. Collegare il trasporto. MCP entra in un ciclo leggi-gestisci-scrivi su stdio fino alla fine del file. REST e gRPC costruiscono la propria tabella di route o di servizi a partire dai livelli rilevati e affidano il ciclo delle richieste a RoadRunner.

A quel punto, una richiesta segue questo flusso: autenticazione (REST e gRPC), risoluzione dello strumento o dell’operazione, esecuzione del gate di conferma per le operazioni ApprovalRequired, esecuzione sul motore e restituzione del risultato. Vedere Avvio e individuazione.

A livello concettuale, i tre trasporti condividono il registro, la configurazione e il gate, ma sono processi indipendenti. Avviarne uno non avvia gli altri.

TrasportoPunto di ingressoQuando sceglierlo
MCPbin/nextpdf-mcpUn client IA locale che avvia il server come sottoprocesso attendibile.
RESTbin/nextpdf-serverClient HTTP in rete, con interfaccia descritta da un documento OpenAPI 3.1.
gRPCbin/nextpdf-grpcClient tipizzati e in streaming, tramite il servizio nextpdf.connect.v1.NextPDFConnect.

Scegliere i trasporti in base al profilo RoadRunner che si esegue: .rr.yaml (solo REST), .rr.grpc.yaml (solo gRPC) o .rr.full.yaml (entrambi). Il trasporto MCP è un semplice sottoprocesso e non richiede alcun supervisore. I dettagli di protocollo per ciascun trasporto sono riportati in Trasporto MCP, Trasporto REST e Trasporto gRPC.

Eseguire i trasporti di rete sotto RoadRunner con store condivisi e chiavi montate come segreti. Il profilo combinato consente a REST e gRPC di condividere un unico supervisore.

Percorso o impostazioneScopo
.rr.full.yamlProfilo REST e gRPC combinato sotto un unico supervisore.
NEXTPDF_API_KEYS_FILEPercorso di un file di chiavi API montato come segreto e ricaricato a caldo.
NEXTPDF_REDIS_HOSTAbilita gli store di rate limiting, idempotenza e documenti con backend Redis per i pool con più worker.
NEXTPDF_WORKER_COUNT / NEXTPDF_GRPC_WORKER_COUNTDimensionamento del pool di worker per i pool HTTP e gRPC.
Directory di base per l’outputVolume dedicato con permessi del filesystem a privilegio minimo per gli strumenti che producono file.

L’esempio shell seguente avvia il profilo combinato con chiavi montate come segreti e uno store Redis condiviso. Non contiene segreti nel file in sé; le chiavi sono montate in /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

Per un pool con più worker, configurare Redis e verificare che ext-redis sia presente nell’immagine in esecuzione; senza l’estensione, gli store di rate limiting, idempotenza e documenti restano per singolo worker. Vedere Distribuzione.

Registro degli strumenti e risoluzione dei livelli

Sezione intitolata “Registro degli strumenti e risoluzione dei livelli”

NextPDF\Server\ToolRegistry (src/ToolRegistry.php) costruisce il catalogo all’avvio. Il livello è dichiarato come invariante: ogni strumento restituisce il proprio tier() e riskLevel(); il registro non deduce mai il livello dal namespace o dal packaging.

  1. Il livello core si registra incondizionatamente: gli strumenti di documento e di diagnostica, più generate_barcode quando il registro core degli encoder di codici a barre è presente, più parse_pdf soltanto quando NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLED è true o 1.
  2. I provider Pro ed Enterprise si registrano quando le rispettive classi provider, verificate con class_exists(), vengono risolte. Un livello assente viene ignorato silenziosamente.
  3. I provider AST e di mutation in bundle vengono registrati nel livello Pro e sono controllati da NEXTPDF_AST_TOOLS_ENABLED e NEXTPDF_MUTATION_TOOLS_ENABLED (entrambi abilitati per impostazione predefinita).
  4. Il filtro dei criteri di sicurezza interseca ogni registrazione con l’allowlist enabled_tools. L’allowlist sottrae; non aggiunge mai. Il conteggio per livello include solo gli strumenti ammessi dai criteri.

I conteggi per livello risultanti e il totale sono riportati nella risposta initialize di MCP e nell’endpoint REST GET /api/v1/capabilities. Qualsiasi totale fisso indicato nel testo va considerato obsoleto; interrogare il server in esecuzione. Vedere Catalogo degli strumenti.

Ogni strumento dichiara uno dei quattro livelli di rischio dell’enum RiskLevel (src/Config/RiskLevel.php): Safe (0), Caution (1), Review (2) e ApprovalRequired (3). La registrazione di audit si applica da Caution in poi. Un override di configurazione può innalzare il rischio di uno strumento; non può mai abbassare il rischio di uno strumento che è ApprovalRequired per progettazione. Il loader della configurazione genera un’eccezione al momento del caricamento e il server rifiuta di avviarsi anziché funzionare con un gate indebolito.

Quando uno strumento ApprovalRequired viene invocato senza un token valido, il ConfirmationGate (src/Mcp/ConfirmationGate.php) restituisce un token di challenge monouso. Il token vincola il nome dello strumento, un nonce casuale e un time-to-live (TTL) di 300 secondi, non gli argomenti, perché, in caso di nuovo tentativo, i client potrebbero riserializzare gli argomenti con un diverso ordinamento delle chiavi. L’agente inoltra la challenge a una persona e reinvoca lo stesso strumento con il token nell’argomento _confirmation_token. Il token viene consumato al momento dell’uso, sbloccando esattamente una chiamata sottoposta al gate.

L’esempio PHP seguente mostra un helper indipendente dal trasporto che esegue una chiamata a uno strumento MCP e, in caso di challenge di conferma, presenta la challenge a un approvatore umano prima di riprovare con il token emesso. Dichiara i tipi stretti, è completamente tipizzato e intercetta l’eccezione più specifica anziché ignorare ogni errore.

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

Collegare McpClientInterface, HumanApproverInterface e ApprovalDeniedException al proprio trasporto e canale di approvazione. Il nuovo tentativo riutilizza gli argomenti originali più il token emesso; non approvare mai automaticamente una challenge senza una decisione umana. Vedere Livelli di rischio HITL.

Estendere il server aggiungendo strumenti e fornendo provider, non modificando il registro.

Punto di estensioneDa usare perVincolo
Una classe che implementa ToolInterfaceUna nuova funzionalità del motore esposta come strumento.Dichiarare tier(), riskLevel(), category() e un inputSchema() come schema JSON; mantenerla come wrapper sottile del motore.
Un provider ToolProviderInterfaceRegistrare un insieme di strumenti per un livello.I provider Pro ed Enterprise vengono individuati tramite class_exists(); non imporre al server il pacchetto proprietario.
Allowlist enabled_toolsDefinire l’ambito del catalogo esposto a privilegio minimo.L’allowlist sottrae soltanto; non può registrare uno strumento assente.
risk_level_overridesRafforzare una distribuzione innalzando il rischio di uno strumento.Solo innalzamento; un abbassamento di uno strumento ApprovalRequired fa fallire l’avvio.
Punti di iniezione per trasporto e workerTestare il server in isolamento.Questi punti di estensione esistono per i test, non per il wiring dell’applicazione.
  1. Scegliere un profilo. Eseguire .rr.yaml, .rr.grpc.yaml o .rr.full.yaml in base ai trasporti da esporre.
  2. Montare le chiavi da un segreto. Puntare NEXTPDF_API_KEYS_FILE a un file segreto; preferire lo store di chiavi su file con ricarica a caldo, così la rotazione non richiede alcun riavvio.
  3. Configurare gli store condivisi. Impostare NEXTPDF_REDIS_HOST e verificare ext-redis per qualsiasi pool con più di un worker; collocare lo store dei job SQLite su un volume su cui tutti i worker possano scrivere.
  4. Terminare il TLS. Eseguire REST dietro un terminatore TLS (Transport Layer Security); eseguire gRPC con TLS reciproco su qualsiasi rete non attendibile, fornendo la chiave del server, il certificato del server e l’autorità di certificazione del client come segreti di distribuzione.
  5. Sondare lo stato di salute. Usare gli endpoint anonimi /healthz e /readyz (REST) oppure le RPC HealthCheck e ReadinessCheck (gRPC) per i probe dell’orchestratore.
  6. Definire l’ambito del catalogo. Limitare enabled_tools all’insieme minimo di cui un’integrazione ha bisogno.

Verificare lo stato di salute di Redis anziché darlo per scontato: il server REST ripiega sugli store in memoria se la connessione Redis configurata fallisce. Vedere Distribuzione e Sicurezza e operazioni.

ErroreDove si manifestaRisposta consigliata
document_id sconosciutoEsecuzione dello strumentoRestituire un errore definito al chiamante; istruirlo a chiamare prima create_pdf.
ETag obsoleto su una mutationStrumento di mutation ASTRileggere il documento con get_document_ast e riprovare con l’ETag aggiornato.
Chiave API mancante o non valida (REST)Middleware di autenticazioneRestituire 401 con una challenge WWW-Authenticate: Bearer; non rivelare quale parte era errata.
Livello non abilitato (REST)AutorizzazioneRestituire 403; il livello della chiave è inferiore al livello dell’operazione.
Route del livello assente (REST)RouterRestituire 404; il pacchetto non è installato. È un comportamento previsto, non un guasto.
Token non valido (gRPC)Autenticatore gRPCFar fallire la chiamata con UNAUTHENTICATED.
Redis irraggiungibileAvvio o runtimeRipiegare sugli store in memoria; avvisare gli operatori e verificare lo stato di salute di Redis.
Percorso di output esterno alla directory di baseStrumento che produce fileRifiutare l’operazione in modalità fail-closed; il percorso viene canonicalizzato e il traversal viene rifiutato.

Esporre gli errori del motore come oggetti di errore definiti, mai come successi silenziosi. Il modello degli errori per ciascun trasporto è descritto nella documentazione di riferimento dell’API.

AspettoPredefinitoQuando eseguire l’override
parse_pdfDisabilitato (attivabile tramite NEXTPDF_MCP_TOOL_PARSE_PDF_ENABLED).Abilitare solo quando un’integrazione richiede l’ispezione strutturale.
enabled_toolsVuota (tutti gli strumenti individuati sono consentiti).Impostare un’allowlist esplicita per le distribuzioni a privilegio minimo.
Override del rischioNessuno.Innalzare il rischio per una distribuzione irrobustita; non tentare mai un abbassamento.
document_ttl / max_documents1800 secondi / 50 documenti.Abbassare per le distribuzioni sensibili alla residenza dei dati o con vincoli di memoria.
allow_file_outputAbilitato.Impostare su false per le distribuzioni stateless e sensibili alla residenza dei dati.
Numero di workerQuattro (HTTP), due (gRPC).Dimensionare in base alla latenza osservata e ai core disponibili.
Listener RESTHTTP in chiaro dietro un terminatore TLS.Terminare sempre il TLS a monte; non esporre mai testo in chiaro su una rete non attendibile.
gRPC su reti non attendibiliTLS reciproco.Obbligatorio; non eseguire mai un listener gRPC in chiaro su una rete non attendibile.
  • I test del registro verificano che un livello Pro o Enterprise assente venga ignorato silenziosamente e che il catalogo core si registri comunque.
  • I test dell’allowlist verificano che enabled_tools sottragga e non aggiunga mai uno strumento che il registro non ha individuato.
  • I test del gate di conferma verificano che uno strumento ApprovalRequired restituisca una challenge alla prima chiamata e venga eseguito una sola volta con un token monouso valido, nonché che il token scada dopo il suo TTL.
  • I test di abbassamento verificano che una voce risk_level_overrides che indebolisce uno strumento ApprovalRequired faccia fallire l’avvio.
  • I test di autenticazione coprono chiavi mancanti, malformate, disabilitate e scadute su REST (401 con WWW-Authenticate) e gRPC (UNAUTHENTICATED), e il rifiuto quando il livello non è abilitato (403).
  • I test di concorrenza verificano che un ETag obsoleto faccia fallire una mutation e che una idempotency_key ripetuta riproduca il risultato memorizzato nella cache.
  • I test di contenimento dei percorsi verificano che un percorso di output che si risolve all’esterno della directory di base venga rifiutato.
  • Mantenere le fixture piccole e non sensibili; non eseguire mai il commit di una chiave API reale o del contenuto di un documento.