Conduza uma sessão de documento de agente por MCP
Panorama geral
Seção intitulada “Panorama geral”Esta é uma sessão de agente completa com o servidor Model Context
Protocol (MCP) do NextPDF Connect, mensagem por mensagem: initialize,
tools/list, seis invocações de tools/call que montam um resumo de
projeto de uma página e o ciclo com humano no circuito (HITL) que protege
a gravação final do arquivo. Cada mensagem JSON-RPC abaixo foi capturada
literalmente de um processo bin/nextpdf-mcp em execução (apenas
ferramentas do tier core) e, então, higienizada de exatamente duas
formas: o token de confirmação de uso único é mostrado como
confirm_<single-use-hex> e o diretório temporário do sistema da máquina
é abreviado para C:\Temp. Identificadores, schemas, posições e
contagens de bytes são exatamente o que o servidor enviou.
Instalação
Seção intitulada “Instalação”composer require nextpdf/serverConfigure o transporte stdio no seu host MCP — para o Claude Desktop (os hosts iniciam o comando a partir do próprio diretório, então use um caminho absoluto; o transporte stdio não precisa de API key, ao contrário do transporte REST):
{ "mcpServers": { "nextpdf": { "command": "php", "args": ["/absolute/path/to/your/project/vendor/bin/nextpdf-mcp"] } }}O servidor fala JSON-RPC 2.0 delimitado por quebra de linha em stdin/stdout e mantém a saída do protocolo estritamente separada dos diagnósticos: as linhas de inicialização e de auditoria vão para stderr, nunca para stdout.
Visão conceitual
Seção intitulada “Visão conceitual”Uma sessão de documento do MCP tem estado. create_pdf abre um documento
no armazenamento em memória do servidor e retorna um document_id; toda
chamada posterior aponta para esse identificador. As ferramentas de conteúdo
(set_font, add_text, add_table) são executadas imediatamente no
nível de risco Cautela, com registro de auditoria; preview_layout é uma
leitura Segura; e output_pdf com um file_path é Aprovação Obrigatória
— não é executada na primeira chamada. Em vez disso, o servidor retorna
um desafio com um token de uso único, o agente repassa o desafio ao
humano e apenas uma nova chamada que carregue _confirmation_token
executa a gravação. Os documentos deixados no armazenamento expiram após
o tempo de vida configurado (30 minutos por padrão).
As mesmas chamadas de ferramenta conduzem o motor de ferramentas sobre REST e gRPC — os transportes compartilham um único executor — então tudo aqui, exceto o enquadramento stdio, se aplica igualmente. Veja Renderize uma fatura de ponta a ponta sobre REST para o mesmo motor na superfície HTTP.
Superfície da API
Seção intitulada “Superfície da API”| Ferramenta | Papel nesta sessão | Nível de risco |
|---|---|---|
create_pdf | Abre o documento, obtém document_id | Cautela |
set_font | Seleciona a fonte do título, depois a do corpo | Cautela |
add_text | Linha do título, depois o parágrafo de introdução | Cautela |
add_table | Tabela de checklist com responsável/prazo | Cautela |
preview_layout | Lê o estado do layout antes da saída | Seguro |
output_pdf (modo de arquivo) | Grava o PDF — com barreira | Aprovação Obrigatória |
A implantação capturada aqui registrou 20 ferramentas (13 core, 6 Pro, 1
Enterprise — as contagens aparecem na resposta de initialize abaixo);
esta sessão usa apenas ferramentas core, então roda sem alterações em uma
instalação somente open source. O catálogo de referência é a resposta de
tools/list do seu próprio servidor, e a escala de risco é definida na
referência dos níveis de risco HITL.
A sessão, mensagem por mensagem
Seção intitulada “A sessão, mensagem por mensagem”1. Inicialize a conexão
Seção intitulada “1. Inicialize a conexão”O cliente abre a sessão e informa a versão do seu protocolo:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "planning-agent", "version": "1.0.0" } }}O servidor confirma a versão do protocolo e declara suas capacidades, incluindo as contagens de ferramentas por tier e que a barreira HITL está habilitada:
{ "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" } }}O cliente confirma com uma notificação (as notificações não carregam id
e não recebem resposta):
{ "jsonrpc": "2.0", "method": "notifications/initialized"}2. Descubra as ferramentas
Seção intitulada “2. Descubra as ferramentas”{ "jsonrpc": "2.0", "id": 2, "method": "tools/list"}A resposta completa lista todas as 20 ferramentas registradas com seus schemas de entrada completos. Aqui, ela aparece reduzida às duas ferramentas que abrem e fecham esta sessão — as 18 entradas omitidas têm o mesmo formato:
{ "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 } } ] }}Observe o schema de output_pdf: file_path é opcional, e as anotações
carregam openWorldHint: true — a ferramenta pode afetar o mundo fora da
sessão, e é exatamente por isso que o modo de arquivo tem barreira.
3. Abra o documento
Seção intitulada “3. Abra o 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" } }}Todo resultado de ferramenta chega duas vezes em uma mensagem: um bloco
de texto content legível por humanos e um structuredContent legível
por máquina. Leia structuredContent.document_id e encadeie-o em cada
chamada seguinte.
4. Adicione o título
Seção intitulada “4. Adicione o título”Defina uma fonte em negrito de 16 pontos e, então, posicione o título:
{ "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. Adicione o parágrafo do corpo
Seção intitulada “5. Adicione o parágrafo do corpo”De volta a uma fonte normal de 11 pontos para o texto de introdução;
width: 0 seleciona o layout multi-célula de largura total:
{ "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. Adicione a tabela de checklist
Seção intitulada “6. Adicione a tabela de 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 } } }}Cada chamada de conteúdo retorna a position atualizada do cursor, então
o agente sempre sabe onde o próximo elemento vai cair.
7. Pré-visualize antes de pedir aprovação
Seção intitulada “7. Pré-visualize antes de pedir aprovação”preview_layout é uma chamada Segura, somente leitura — um agente
bem-comportado verifica o que construiu antes de pedir a um humano que
aprove uma gravação:
{ "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. Solicite a gravação do arquivo — a barreira responde primeiro
Seção intitulada “8. Solicite a gravação do arquivo — a barreira responde primeiro”O agente pede a output_pdf que grave o resumo finalizado em disco,
mantendo o documento vivo (destroy: false) caso o humano rejeite e seja
necessário recorrer à saída em 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 } }}O arquivo não é gravado. Como o modo de arquivo é Aprovação Obrigatória, o servidor responde, em vez disso, com um desafio de confirmação:
{ "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. O humano aprova — chame novamente com o token
Seção intitulada “9. O humano aprova — chame novamente com o token”O agente repassa o texto do desafio ao humano. Após a aprovação, ele
chama output_pdf novamente com os mesmos argumentos mais
_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>" } }}O token é consumido, a gravação é executada e o resultado informa o arquivo gravado:
{ "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 } }}Verifique o arquivo gravado
Seção intitulada “Verifique o arquivo gravado”A sessão gravou kickoff-brief.pdf (3.612 bytes, uma página,
correspondendo a structuredContent.file_size e page_count). Saída capturada de
qpdf --check para esse arquivo exato:
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 detectIsso é uma verificação estrutural, nas palavras do próprio qpdf — não uma determinação de conformidade.
Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- A nova chamada deve repetir os mesmos argumentos. O token de
confirmação está vinculado ao nome da ferramenta mais um digest
canônico dos argumentos para os quais foi emitido. Chamar novamente com
qualquer coisa alterada — mesmo inverter
destroy— não consome o token; o servidor responde, em vez disso, com um novo desafio. Repita os argumentos exatamente e adicione apenas_confirmation_token. - O token é de uso único e expira. O desafio informa o prazo de expiração (300 segundos). Após a expiração ou o consumo, a próxima chamada com barreira recebe um novo desafio; repasse o novo.
- A saída de arquivo cai dentro de um diretório da lista de
permissões. O servidor rejeita um
file_pathfora do seu diretório temporário configurado comOutput path rejected by security policy. A raiz padrão da lista de permissões énextpdf-mcpsob o diretório temporário do sistema; os operadores a alteram com a configuraçãotemp_diremnextpdf-mcp.yaml. - O modo base64 não tem barreira.
output_pdfsemfile_pathretorna o PDF como base64 no nível Revisão, sem efeito colateral no sistema de arquivos — veja Exija aprovação humana para a saída de arquivo para conhecer esse limite em profundidade. - Um desafio é um resultado, não um erro. A mensagem de desafio chega
com
isError: false; uma aprovação pendente é uma pausa no fluxo de trabalho. Não repita em loop e nunca fabrique um token. - Notificações não recebem resposta. Após
notifications/initialized, não fique bloqueado esperando por uma linha de resposta.
Desempenho
Seção intitulada “Desempenho”A sessão é totalmente em memória de ponta a ponta: as chamadas de conteúdo retornaram em milissegundos na execução capturada, e o tempo total é dominado pelo ciclo de aprovação humana, que é o propósito da barreira. O armazenamento de documentos mantém uma sessão por 30 minutos de tempo ocioso por padrão (no máximo 50 documentos), então uma aprovação lenta não perde o documento construído — mas um documento abandonado é descartado.
Notas de segurança
Seção intitulada “Notas de segurança”- Trate o token de confirmação como um segredo de uso único. Repasse o texto do desafio ao humano; não registre o token em log nem o persista. Esta página oculta o token capturado exatamente por essa razão.
- A trilha de auditoria fica no stderr. Toda execução no nível Cautela ou acima é registrada em auditoria (ferramenta, risco, argumentos, resultado) via PSR-3, com os parâmetros sensíveis ocultados. Os diagnósticos nunca se misturam ao fluxo do protocolo.
- A lista de permissões de caminhos é o limite do sistema de
arquivos. Aponte
temp_dirpara um diretório dedicado à saída do Connect; não a amplie para um local de uso geral. - Os níveis de risco só sobem. Uma sobrescrita de operador em
nextpdf-mcp.yamlpode elevar o nível de risco de uma ferramenta, mas nunca pode rebaixaroutput_pdfabaixo de Aprovação Obrigatória.
Conformidade
Seção intitulada “Conformidade”Esta receita não faz nenhuma afirmação normativa de conformidade com
padrões. Ela documenta o transporte stdio do MCP (JSON-RPC 2.0, versão de
protocolo 2025-06-18 conforme negociada na troca de initialize
capturada) e o contrato de risco e confirmação do servidor. A etapa
qpdf --check acima confirma apenas a integridade estrutural do arquivo
gravado; a conformidade com um padrão é determinada por um validador
independente, não afirmada pelo software produtor.
Veja também
Seção intitulada “Veja também”- Exija aprovação humana para a saída de arquivo — a barreira de confirmação em profundidade, incluindo o caminho de rejeição.
- Renderize uma fatura de ponta a ponta sobre REST — o mesmo motor de ferramentas sobre HTTP, com a transcrição de rede capturada.
- Gere seu primeiro PDF — a menor sessão do Connect.
- Convenções das receitas do Connect — o contrato que toda receita do Connect segue.
- Níveis de risco HITL — a escala de risco canônica e a resolução de política.
- Catálogo de ferramentas — o catálogo de ferramentas de referência.