Gestire una sessione documentale di un agente tramite MCP
In sintesi
Sezione intitolata “In sintesi”Questa è una sessione completa di un agente con il server Model
Context Protocol (MCP) di NextPDF Connect, messaggio per messaggio:
initialize, tools/list, sei invocazioni tools/call che costruiscono
un brief di progetto di una pagina e il round trip con intervento umano
(HITL) che sottopone al gate la scrittura finale del file. Ogni messaggio
JSON-RPC riportato di seguito è stato catturato alla lettera da un
processo bin/nextpdf-mcp reale (soli strumenti di livello core), quindi
sanificato in esattamente due modi: il token di conferma monouso è
mostrato come confirm_<single-use-hex> e la directory temporanea di
sistema della macchina è abbreviata in C:\Temp. Identificatori, schemi,
posizioni e conteggi di byte sono esattamente quelli inviati dal server.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/serverConfigurare il trasporto stdio nel proprio host MCP — per Claude Desktop (gli host lanciano il comando dalla propria directory, quindi usare un percorso assoluto; il trasporto stdio non richiede alcuna API key, a differenza del trasporto REST):
{ "mcpServers": { "nextpdf": { "command": "php", "args": ["/absolute/path/to/your/project/vendor/bin/nextpdf-mcp"] } }}Il server parla JSON-RPC 2.0 delimitato da newline su stdin/stdout e mantiene l’output di protocollo rigorosamente separato dalla diagnostica: le righe di avvio e di audit vanno su stderr, mai su stdout.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Una sessione documentale MCP è stateful. create_pdf apre un documento
nello store in memoria del server e restituisce un document_id; ogni
chiamata successiva punta a quell’identificatore. Gli strumenti di
contenuto (set_font, add_text, add_table) vengono eseguiti
immediatamente al livello di rischio Cautela con registrazione di audit;
preview_layout è una lettura Sicura; e output_pdf con un file_path
è Approvazione richiesta — non viene eseguito alla prima chiamata. Il
server restituisce invece una sfida con un token monouso, l’agente
inoltra la sfida alla persona e solo un nuovo richiamo che trasporta
_confirmation_token esegue la scrittura. I documenti lasciati nello
store scadono dopo il time to live configurato (30 minuti per
impostazione predefinita).
Le stesse chiamate agli strumenti guidano il motore degli strumenti su REST e gRPC — i trasporti condividono un unico executor — quindi tutto quanto riportato qui, tranne il framing stdio, vale anche per essi. Vedere Eseguire il rendering di una fattura end-to-end tramite REST per lo stesso motore sulla superficie HTTP.
Superficie API
Sezione intitolata “Superficie API”| Strumento | Ruolo in questa sessione | Livello di rischio |
|---|---|---|
create_pdf | Apre il documento, ottiene document_id | Cautela |
set_font | Seleziona il carattere dell’intestazione, poi del corpo | Cautela |
add_text | Riga del titolo, poi paragrafo introduttivo | Cautela |
add_table | Tabella checklist responsabile/scadenza | Cautela |
preview_layout | Legge lo stato del layout prima dell’output | Sicuro |
output_pdf (modalità file) | Scrive il PDF — con gate | Approvazione richiesta |
Il deployment catturato qui ha registrato 20 strumenti (13 core, 6 Pro, 1
Enterprise — i conteggi compaiono nella risposta initialize più avanti);
questa sessione usa solo strumenti core, quindi viene eseguita senza
modifiche su un’installazione esclusivamente open source. Il catalogo di
riferimento è la risposta tools/list del proprio server e la scala dei
rischi è definita nel
riferimento ai livelli di rischio HITL.
La sessione, messaggio per messaggio
Sezione intitolata “La sessione, messaggio per messaggio”1. Inizializzare la connessione
Sezione intitolata “1. Inizializzare la connessione”Il client apre la sessione e dichiara la propria versione di protocollo:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "planning-agent", "version": "1.0.0" } }}Il server conferma la versione di protocollo e dichiara le proprie capacità, inclusi i conteggi degli strumenti per livello e il fatto che il gating HITL è abilitato:
{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2025-06-18", "capabilities": { "tools": { "listChanged": false }, "nextpdf": { "tiers": { "core": 13, "pro": 6, "enterprise": 1 }, "tool_count": 20, "risk_model_version": 1, "hitl_enabled": true } }, "serverInfo": { "name": "NextPDF Connect", "version": "1.0.0" } }}Il client conferma con una notifica (le notifiche non trasportano alcun
id e non ricevono risposta):
{ "jsonrpc": "2.0", "method": "notifications/initialized"}2. Individuare gli strumenti
Sezione intitolata “2. Individuare gli strumenti”{ "jsonrpc": "2.0", "id": 2, "method": "tools/list"}La risposta completa elenca tutti e 20 gli strumenti registrati con i loro schemi di input completi. Qui è mostrata abbreviata ai due strumenti che aprono e chiudono questa sessione — le 18 voci omesse hanno la stessa forma:
{ "jsonrpc": "2.0", "id": 2, "result": { "tools": [ { "name": "create_pdf", "description": "Create a new PDF document and return a document_id for subsequent operations", "inputSchema": { "type": "object", "properties": { "page_size": { "type": "string", "description": "Page size name (e.g. \"A4\", \"Letter\", \"Legal\", \"A3\")", "default": "A4" }, "orientation": { "type": "string", "enum": [ "portrait", "landscape" ], "description": "Page orientation", "default": "portrait" }, "title": { "type": "string", "description": "Document title metadata" }, "author": { "type": "string", "description": "Document author metadata" } }, "required": [] }, "annotations": { "destructiveHint": false, "idempotentHint": false } }, { "name": "output_pdf", "description": "Finalize the PDF and output to file or return as base64", "inputSchema": { "type": "object", "properties": { "document_id": { "type": "string", "description": "The document_id returned by create_pdf" }, "file_path": { "type": "string", "description": "Absolute file path to save the PDF. If omitted, returns base64-encoded PDF data." }, "destroy": { "type": "boolean", "description": "Whether to remove the document from the store after output", "default": true } }, "required": [ "document_id" ] }, "annotations": { "destructiveHint": false, "openWorldHint": true } } ] }}Si noti lo schema di output_pdf: file_path è opzionale e le
annotazioni portano openWorldHint: true — lo strumento può agire sul
mondo esterno alla sessione, che è esattamente il motivo per cui la
modalità file è sottoposta al gate.
3. Aprire il documento
Sezione intitolata “3. Aprire il documento”{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "create_pdf", "arguments": { "page_size": "A4", "orientation": "portrait", "title": "Project kickoff brief", "author": "Planning agent" } }}{ "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"page_count\":1,\"page_size\":\"A4\",\"orientation\":\"portrait\"}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "page_count": 1, "page_size": "A4", "orientation": "portrait" } }}Ogni risultato di uno strumento arriva due volte in un unico messaggio:
un blocco di testo content leggibile dall’uomo e structuredContent
leggibile dalla macchina. Leggere structuredContent.document_id e
propagarlo attraverso ogni chiamata successiva.
4. Aggiungere l’intestazione
Sezione intitolata “4. Aggiungere l’intestazione”Impostare un carattere in grassetto da 16 punti, quindi collocare il titolo:
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "set_font", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "family": "helvetica", "style": "B", "size": 16 } }}{ "jsonrpc": "2.0", "id": 4, "result": { "content": [ { "type": "text", "text": "Font set to helvetica B 16pt on document doc_3b9f435efa0f32d1da7a131d." } ] }}{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "add_text", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "text": "Project kickoff brief" } }}{ "jsonrpc": "2.0", "id": 5, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":16,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 16, "page": 0 } } }}5. Aggiungere il paragrafo del corpo
Sezione intitolata “5. Aggiungere il paragrafo del corpo”Tornare a un carattere normale da 11 punti per il testo introduttivo;
width: 0 seleziona un layout multi-cella a piena larghezza:
{ "jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": { "name": "set_font", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "family": "helvetica", "style": "", "size": 11 } }}{ "jsonrpc": "2.0", "id": 6, "result": { "content": [ { "type": "text", "text": "Font set to helvetica 11pt on document doc_3b9f435efa0f32d1da7a131d." } ] }}{ "jsonrpc": "2.0", "id": 7, "method": "tools/call", "params": { "name": "add_text", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "text": "Prepared by the planning agent for the 14 July kickoff. Scope, owners, and the first-week checklist are tabled below.", "width": 0, "line_height": 6 } }}{ "jsonrpc": "2.0", "id": 7, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":29.75,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 29.75, "page": 0 } } }}6. Aggiungere la tabella della checklist
Sezione intitolata “6. Aggiungere la tabella della checklist”{ "jsonrpc": "2.0", "id": 8, "method": "tools/call", "params": { "name": "add_table", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "html": "<table><tr><th>Work item</th><th>Owner</th><th>Due</th></tr><tr><td>Repository bootstrap</td><td>Devon</td><td>2026-07-15</td></tr><tr><td>CI pipeline</td><td>Ana</td><td>2026-07-17</td></tr><tr><td>Staging deploy</td><td>Priya</td><td>2026-07-21</td></tr></table>" } }}{ "jsonrpc": "2.0", "id": 8, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":84.75,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 84.75, "page": 0 } } }}Ogni chiamata di contenuto restituisce la position aggiornata del
cursore, così l’agente sa sempre dove verrà collocato l’elemento
successivo.
7. Anteprima prima di chiedere l’approvazione
Sezione intitolata “7. Anteprima prima di chiedere l’approvazione”preview_layout è una chiamata Sicura e di sola lettura — un agente che
si comporta correttamente verifica ciò che ha costruito prima di chiedere
a una persona di approvare una scrittura:
{ "jsonrpc": "2.0", "id": 9, "method": "tools/call", "params": { "name": "preview_layout", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d" } }}{ "jsonrpc": "2.0", "id": 9, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"total_pages\":1,\"current_page\":0,\"page_dimensions\":{\"width\":595.276,\"height\":841.89},\"margins\":{\"top\":10,\"right\":10,\"bottom\":10,\"left\":10},\"cursor_position\":{\"x\":10,\"y\":84.75}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "total_pages": 1, "current_page": 0, "page_dimensions": { "width": 595.276, "height": 841.89 }, "margins": { "top": 10, "right": 10, "bottom": 10, "left": 10 }, "cursor_position": { "x": 10, "y": 84.75 } } }}8. Richiedere la scrittura del file — il gate risponde per primo
Sezione intitolata “8. Richiedere la scrittura del file — il gate risponde per primo”L’agente chiede a output_pdf di scrivere su disco il brief completato,
mantenendo il documento in vita (destroy: false) nel caso in cui la
persona rifiuti e sia necessario ripiegare sull’output in base64:
{ "jsonrpc": "2.0", "id": 10, "method": "tools/call", "params": { "name": "output_pdf", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "destroy": false } }}Il file non viene scritto. Poiché la modalità file è Approvazione richiesta, il server risponde invece con una sfida di conferma:
{ "jsonrpc": "2.0", "id": 10, "result": { "content": [ { "type": "text", "text": "⚠️ CONFIRMATION REQUIRED\n\nOperation: output_pdf\nDescription: Finalize the PDF and output to file or return as base64\n\nTo proceed, call output_pdf again with parameter _confirmation_token: \"confirm_<single-use-hex>\"\nExpires in 300 seconds." } ], "isError": false }}9. La persona approva — richiamare con il token
Sezione intitolata “9. La persona approva — richiamare con il token”L’agente inoltra il testo della sfida alla persona. In caso di
approvazione, chiama nuovamente output_pdf con gli stessi argomenti
più _confirmation_token:
{ "jsonrpc": "2.0", "id": 11, "method": "tools/call", "params": { "name": "output_pdf", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "destroy": false, "_confirmation_token": "confirm_<single-use-hex>" } }}Il token viene consumato, la scrittura viene eseguita e il risultato riporta il file scritto:
{ "jsonrpc": "2.0", "id": 11, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"file_path\":\"C:\\\\Temp\\\\nextpdf-mcp\\\\kickoff-brief.pdf\",\"file_size\":3612,\"page_count\":1,\"destroyed\":false}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "file_size": 3612, "page_count": 1, "destroyed": false } }}Verificare il file scritto
Sezione intitolata “Verificare il file scritto”La sessione ha scritto kickoff-brief.pdf (3.612 byte, una pagina,
corrispondenti a structuredContent.file_size e page_count). Output di
qpdf --check catturato per quel file esatto:
checking kickoff-brief.pdfPDF Version: 2.0File is not encryptedFile is not linearizedNo syntax or stream encoding errors found; the file may still containerrors that qpdf cannot detectSi tratta di un controllo strutturale, per usare le parole di qpdf — non di una determinazione di conformità.
Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Il nuovo richiamo deve ripetere gli stessi argomenti. Il token di
conferma è associato al nome dello strumento più un digest canonico
degli argomenti per cui è stato emesso. Richiamare con qualcosa di
modificato — anche solo invertendo
destroy— non consuma il token; il server risponde invece con una nuova sfida. Ripetere esattamente gli argomenti e aggiungere solo_confirmation_token. - Il token è monouso e scade. La sfida indica la scadenza (300 secondi). Dopo la scadenza o il consumo, la successiva chiamata sottoposta al gate riceve una nuova sfida; inoltrare la nuova.
- L’output dei file finisce all’interno di una directory in
allow-list. Il server rifiuta un
file_pathesterno alla directory temporanea configurata conOutput path rejected by security policy. La radice di allow-list predefinita ènextpdf-mcpsotto la directory temporanea di sistema; gli operatori la modificano con l’impostazionetemp_dirinnextpdf-mcp.yaml. - La modalità base64 non è sottoposta al gate.
output_pdfsenzafile_pathrestituisce il PDF come base64 al livello Revisione, senza alcun effetto collaterale sul filesystem — vedere Richiedere l’approvazione umana per l’output dei file per quel confine in dettaglio. - Una sfida è un risultato, non un errore. Il messaggio di sfida
arriva con
isError: false; un’approvazione in sospeso è una pausa nel flusso di lavoro. Non riprovare in ciclo e non fabbricare mai un token. - Le notifiche non ricevono risposta. Dopo
notifications/initialized, non bloccarsi in attesa di una riga di risposta.
Prestazioni
Sezione intitolata “Prestazioni”La sessione si svolge interamente in memoria: le chiamate di contenuto hanno risposto in millisecondi nell’esecuzione catturata e il tempo complessivo è dominato dal round trip di approvazione umana, che è lo scopo del gate. Lo store dei documenti mantiene una sessione per 30 minuti di inattività per impostazione predefinita (massimo 50 documenti), quindi un’approvazione lenta non perde il documento costruito — ma uno abbandonato viene rimosso.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”- Trattare il token di conferma come un segreto monouso. Inoltrare il testo della sfida alla persona; non registrare il token nei log né conservarlo. Questa pagina oscura il token catturato esattamente per questo motivo.
- La traccia di audit è su stderr. Ogni esecuzione di livello Cautela o superiore viene registrata nell’audit (strumento, rischio, argomenti, esito) tramite PSR-3, con i parametri sensibili oscurati. La diagnostica non si mescola mai nel flusso di protocollo.
- L’allow-list dei percorsi è il confine del filesystem. Puntare
temp_dira una directory dedicata all’output di Connect; non ampliarla a una posizione generica. - I livelli di rischio possono solo aumentare. Un override
dell’operatore in
nextpdf-mcp.yamlpuò innalzare il livello di rischio di uno strumento ma non può mai abbassareoutput_pdfsotto Approvazione richiesta.
Conformità
Sezione intitolata “Conformità”Questa ricetta non formula alcuna dichiarazione normativa sugli standard.
Documenta il trasporto stdio di MCP (JSON-RPC 2.0, versione di protocollo
2025-06-18 come negoziata nello scambio initialize catturato) e il
contratto di rischio e conferma del server. Il passaggio qpdf --check
qui sopra conferma solo l’integrità strutturale del file scritto; la
conformità a uno standard è determinata da un validatore indipendente,
non asserita dal software che lo produce.
Vedere anche
Sezione intitolata “Vedere anche”- Richiedere l’approvazione umana per l’output dei file — il gate di conferma in dettaglio, compreso il percorso di rifiuto.
- Eseguire il rendering di una fattura end-to-end tramite REST — lo stesso motore degli strumenti su HTTP, con la trascrizione catturata del wire.
- Generare il primo PDF — la sessione Connect più piccola.
- Convenzioni delle ricette Connect — il contratto che ogni ricetta Connect segue.
- Livelli di rischio HITL — la scala dei rischi canonica e la risoluzione delle policy.
- Catalogo degli strumenti — il catalogo degli strumenti di riferimento.