pdfnative

Motor de PDF local para agentes de IA. TypeScript sem dependências, PDF/A, assinaturas, 800+ páginas/seg.

Documentação

pdfnative-mcp

Servidor MCP para geração de PDF, arquivamento PDF/A, troca de impressão PDF/X-4, tipografia refinada, assinatura PAdES com validação de longo prazo, AcroForms, mesclagem/divisão, criptografia e pré-visualização de layout — 28 ferramentas e 7 prompts no mecanismo pdfnative (sem dependências, compatível com ISO 32000-1), para Claude Desktop, Cursor, ChatGPT e qualquer cliente do Model Context Protocol.

npm version npm downloads Node version License: MIT CI MCP pdfnative TypeScript OpenSSF Scorecard CodeQL


✨ Recursos

pdfnative-mcp expõe 28 ferramentas de nível de produção para qualquer host MCP:

FerramentaFinalidade
generate_basic_pdfDocumentos de várias páginas a partir de 13 tipos de blocos — heading, paragraph, list, table, image (JPEG/PNG), link, toc (sumário impresso), barcode, svg, formField, chart, pageBreak, spacer — todos os DocumentBlock que o mecanismo oferece. Quebras de linha incorporadas são divididas automaticamente em parágrafos. Opcionais: pdfA, pdfx (novo na v1.7.0), print, metadata, embedFonts, watermark, outline, opções de layout (pageSize, margins, headerTemplate / footerTemplate, compress, debug, encrypt), typography (novo na v1.7.0) e cores CMYK (novo na v1.7.0).
inspect_layout (novo na v1.6.0)Simulação de paginação somente leitura do mesmo blocks (+ title, footerText, pdfA, normalize, embedFonts, pageSize, margins, headerTemplate, footerTemplate, typography): contagem de páginas e onde cada bloco é posicionado, sem gerar PDF.
add_barcodeQR Code, Code 128, EAN-13, Data Matrix, PDF417 — incorporados em um PDF de página única.
add_international_text27 alfabetos Unicode — Lao, Tai Tham, New Tai Lue, Tai Le e Cham (novo na v1.7.0) — além de Latim, matemática e emoji coloridos COLRv1 (sequências de bandeira / ZWJ, modificadores de tom de pele), com modelagem BiDi e OpenType; vários idiomas por documento.
add_tableRelatórios tabulares com campos inteligentes (wrap, repeatHeader, zebra, caption, minRowHeight, cellPadding).
add_formCria um novo PDF interativo com AcroForm contendo campos de texto, áreas de texto, caixas de seleção, botões de opção, listas suspensas, caixas de lista (+ texto de dica placeholder).
read_form_fieldsEnumeração somente leitura da árvore de campos de um AcroForm existente (nomes, tipos, valores, widgets).
fill_formPreenche e/ou achata um AcroForm existente (atualização incremental não destrutiva).
add_chartGráficos vetoriais nativos v2 — barra / barraH / barraEmpilhada / barraEmpilhadaH / linha / área / dispersão / pizza / rosca, eixo secundário, escalas logarítmica e de tempo, rótulos de dados (operadores de caminho PDF puros, compatíveis com PDF/A).
embed_imageIncorpora uma imagem JPEG ou PNG (base64) em um documento PDF com título (texto align, alt para saída marcada).
prepare_signature_placeholderEtapa 1 opcional do fluxo de assinatura — cria um PDF com um espaço reservado /Sig (metadados do signatário, subFilter, reserveTimestamp incorporados).
sign_pdfAssinatura CMS PAdES B-B / B-T (RSA-SHA256/384/512, ECDSA-SHA256 P-256; profile: 'pades', timestamp, certChainDerBase64, múltiplas assinaturas, signingTime fixável). Injeta automaticamente um espaço reservado quando necessário.
add_ltv (novo na v1.6.0)PAdES B-LT — incorpora um /DSS com certificados + material OCSP/CRL (provedor configurado pelo operador, ou material offline fornecido pelo chamador).
timestamp_pdf (novo na v1.6.0)PAdES B-LTA — anexa um /DocTimeStamp RFC 3161 da TSA configurada pelo operador; execute novamente para estender a cadeia de arquivamento.
verify_pdfVerifica cada assinatura PAdES e carimbo de tempo do documento (integridade + valor da assinatura + confiança opcional da cadeia; um /DocTimeStamp conta no allValid como qualquer assinatura); ltv: true relata o nível B-B…B-LTA.
validate_pdfValida um PDF marcado para conformidade estrutural PDF/UA (ISO 14289-1), ou com standard: 'pdf-x-4' (novo na v1.7.0) os pré-requisitos estruturais de PDF/X-4 (ISO 15930-7) — somente leitura, não é uma pré-verificação certificada.
add_attachmentGera um documento PDF/A-3 com arquivos incorporados (faturas Factur-X / ZUGFeRD).
extract_attachmentsExtração somente leitura de arquivos incorporados (round-trip XML Factur-X / ZUGFeRD) com cargas úteis byte a byte.
extract_textExtração de texto Unicode (resolve /ToUnicode) com execuções posicionadas opcionais; abre PDFs criptografados via password.
inspect_pdfInspeção somente leitura: versão do PDF, contagem de páginas, criptografia (+ encryptionInfo preciso), declaração PDF/A, declaração PDF/X (pdfX, novo na v1.7.0), assinaturas (+ inventário, /DSS, carimbos de tempo do documento), caixas de página, /Trapped, anexos, estado do espaço reservado, inventário annotations: true de anotações de página existentes.
update_metadata (novo na v1.6.0)Reescreve /Info título / autor / assunto / palavras-chave (+ XMP, datas incluídas) de um PDF existente como atualização incremental; fixa modDate para bytes reproduzíveis.
encrypt_pdfRe-protege um PDF com AES-128 / AES-256 (senhas de proprietário/usuário, permissões, rotação de senha).
decrypt_pdfEmite uma cópia não criptografada de um documento RC4 / AES-128 / AES-256.
merge_pdfsConcatena 2–50 PDFs em um único via API de árvore de páginas do pdfnative (caixas de página preservadas).
split_pdfDivide um PDF em um documento por intervalo de páginas (saída múltipla).
extract_pagesExtrai um subconjunto arbitrário de páginas para um único PDF.
annotate_pdfAdiciona anotações de marcação (realce, nota, quadrado/círculo, linha, texto livre) como sobreposição visual — não é uma redação.
draft_governance_issueRedige uma issue do GitHub em conformidade com governança localmente para revisão humana; nunca envia, sem rede.

Novo na v1.7.0:

  • 🔤 Tipografia fina — um objeto typography opcional nos nove documentos e em inspect_layout: splitParagraphs com orphans / widows, keepHeadingsWithNext, unitBinding, bindShortWords, punctuationSpacing ('fr', 'fr-CA' ou regras explícitas), opticalMargins, metrics: 'exact', fontFeatures (11 tags OpenType), kerning, hyphenationLanguage. Blocos de parágrafo ganham align (left / right / center / justify), keepWithNext e splittable; blocos de título ganham keepWithNext. Limites honestos: kerning, fontFeatures e o 'fr' espaço estreito sem quebra precisam de embedFonts: true (a Helvetica base-14 degrada 'fr' para 'fr-CA'); tnum / lnum não mudam nada no Noto Sans incluído (diagnóstico TYPOGRAPHY_FEATURE_INEFFECTIVE); nenhum dicionário de hifenização está instalado, então hyphenationLanguage não tem efeito aqui — hifens suaves (U+00AD) são respeitados. Veja docs/guides/TYPOGRAPHY.md.
  • 🎨 CMYK em qualquer lugar onde uma cor é aceita — strings de operando 'c m y k' (0–1) e tuplas percentuais [c, m, y, k] (0–100) ao lado das formas hex / RGB existentes: marcas d'água, modelos de cabeçalho / rodapé, bordas de células de tabela, entradas de contorno, gráficos, blocos link e svg, annotate_pdf. Cada forma de cor da 1.6.0 ainda valida.
  • 🖨️ PDF/X-4 — pdfx: 'pdfx4' em seis ferramentas de geração (generate_basic_pdf, add_table, add_chart, add_barcode, embed_image, add_international_text), perfis CMYK ou Gray outputIntent ao lado de RGB, print.marks.colourBars e validate_pdf { standard: 'pdf-x-4' } para verificar o resultado; inspect_pdf relata a alegação (pdfX, verifique 'pdfx'). Requer o perfil ICC da impressora (classe de dispositivo prtr — nenhum está incluído), precisa de embedFonts: true para um arquivo conforme (PDFX_NO_FONT_ENTRIES caso contrário; strict: true recusa), e é exclusivo com pdfA e encrypt. A validação é estrutural — não é um preflight certificado; o resultado diz isso por si só em caveats[]. Veja docs/guides/PRINT.md.
  • 🌏 27 scripts Unicode — add_international_text aceita lo (Lao), nod (Tai Tham), khb (New Tai Lue), tdd (Tai Le) e cjm (Cham); ha, yo, ig, sw são aliases de latin (marcas de tom se anexam); modificadores de tom de pele emoji renderizam. Tai Tham sob PDF/A deve usar pdfa2b, não pdfa2u (um glifo não tem uma entrada ToUnicode upstream).
  • 🔁 Reprodutível em qualquer host — cada data é escrita em UTC, {date} em um cabeçalho ou rodapé segue o instante fixado, e o operador pode fixar todo o processo com PDFNATIVE_MCP_CREATION_DATE ou SOURCE_DATE_EPOCH (veja Variáveis de ambiente). Não coberto, por design: signingTime, modDate, tokens RFC 3161 e dados de revogação, criptografia, assinaturas ECDSA. Veja docs/guides/REPRODUCIBLE.md.
  • 🚦 strict escala por código de diagnóstico — PDFA_* → PDF_A_COMPLIANCE_VIOLATION, PDFX_* → PDF_X_COMPLIANCE_VIOLATION (novo), qualquer outra coisa → DIAGNOSTIC_ESCALATED (novo). Ambos os novos códigos só podem ser retornados por uma chamada que define strict: true.
  • 🧩 Um sétimo prompt MCP, typography — e print_ready, reproducible_output, pdfa_valid reescritos para CMYK, PDF/X-4, barras de cor e o pin UTC / operador.
  • 🐛 Correções — um tripleto RGB 0–1 (watermark.color, as cores annotate_pdf) agora renderiza a cor que nomeia ([1, 0, 0] costumava renderizar quase preto); qualquer falha inesperada de uma ferramenta que recebe entrada PDF é classificada como PDF_PARSE_FAILED em vez de aparecer sem código.
  • ✅ Fechado upstream — um formulário PDF/A construído com embedFonts: true agora valida sob veraPDF (a fonte AcroForm está incorporada), e inspect_layout mede um bloco toc exatamente como a construção o dispõe.
  • 🧪 Um portão, CI endurecido, docs verificados — npm run gate é a única definição de verde (o servidor construído é dirigido sobre stdio e stdout deve carregar apenas quadros JSON-RPC); veraPDF é bloqueante sobre um corpus de conformidade de 41 arquivos; uma linha de base de bytes de 96 amostras protege a saída; npm run verify:docs mantém cada contagem, versão, ferramenta, código de erro e variável de operador citados nos docs para docs/assets/ecosystem.json e a árvore de origem.
  • 🧾 Catálogo — tools/list cresce para ≈ 306 kB (o fragmento de tipografia e os esquemas de cor ampliados são embutidos em cada ferramenta que os carrega; npx tsx scripts/tool-shape.ts --check o mantém abaixo de 320 KiB e as instruções abaixo de 8 KiB); _meta.apiVersion é 1.7.0.
  • ⬆ Atualização do motor — pdfnative v1.8.0. Sem mudança que quebre a API da ferramenta; os bytes que mudam (subconjuntos TrueType incorporados, print.marks, texto moldado com posicionamento de marca, datas UTC) estão listados sob Upgrade em release-notes/v1.7.0.md.

Novo na v1.6.0:

  • 🧱 Cobertura completa do mecanismo — 13 tipos de blocos — generate_basic_pdf aceita todos os DocumentBlock que o pdfnative oferece: os novos blocos table, image, link, toc, barcode, svg e formField compartilham seu corpo com as ferramentas dedicadas (add_table, embed_image, add_barcode, add_form), de modo que um artefato independente e um bloco inline validam e renderizam de forma idêntica. Regras: link aceita apenas http: / https: / mailto: (caracteres de controle rejeitados); blocos image são limitados (12 M de caracteres base64 cada, 24 MiB decodificados por chamada; PNG deve ser de 8 bits, não entrelaçado, sem alfa ou paleta — rejeitado com uma solução); svg cobre caminhos, formas básicas e <text> (sem transform, <g>, gradientes ou CSS — ignorados silenciosamente; nada é jamais buscado); toc emparelha com outline: 'auto'; formField sob uma alegação de PDF/A relata PDFA_UNEMBEDDED_FORM_FONT; barcode não tem alt (limitação do mecanismo).
  • 📐 Opções de layout nas nove ferramentas de documento — pageSize (padrão A4, Letter, Legal, A3, Tabloid), margins (todos os quatro, 0–200 pt), headerTemplate / footerTemplate com {page} {pages} {title} {date} (um footerTemplate substitui o rodapé padrão, então footerText é ignorado nesse caso; {date} era o relógio de parede do dia da compilação na 1.6.0 — desde a v1.7.0 segue o instante fixado), compress (fluxos FlateDecode — arquivo menor, bytes diferentes; XMP permanece simples sob PDF/A) e debug (retângulos de guia, conteúdo não marcado — não para PDF/UA). Ausentes por padrão, então a saída padrão permanece byte-idêntica.
  • 🔐 Criptografia em tempo de compilação — encrypt em sete ferramentas de documento (generate_basic_pdf, add_table, add_form, add_international_text, embed_image, add_barcode, add_chart): Standard Security Handler, AES-128 padrão / AES-256, mantém o AcroForm (diferente de encrypt_pdf, que reconstrói a árvore de páginas). Exclusivo com pdfA (VALIDATION_ERROR), nunca armazenado em cache; não oferecido em prepare_signature_placeholder (deve permanecer assinável) ou add_attachment (PDF/A-3).
  • 📏 inspect_layout — a 28ª ferramenta: uma simulação de paginação somente leitura sobre os mesmos blocks e entradas de layout, relatando totalPages e a página / x / topo / largura / altura de cada bloco sem renderizar um PDF. Lacuna conhecida do mecanismo na 1.6.0 (corrigida na v1.7.0): um bloco toc era medido como 0 pt, então documentos com um conteúdo impresso podiam paginar uma página depois do previsto.
  • 🔎 inspect_pdf annotations: true — lista cada anotação de página (subtipo, página baseada em 0, retângulo, conteúdo truncado a 200 caracteres, título, cor, quadPoints, URL do link) além de annotationCount; novo check: 'annotations'.
  • 🖼️ Marcas d'água de imagem — watermark.image (JPEG/PNG, opacidade padrão 0,10, próprio limite de 8 MiB) em generate_basic_pdf e add_table, sozinho ou combinado com text (opacidade padrão 0,15); position: 'background' | 'foreground' para ambos. Qualquer opacidade abaixo de 1,0 é rejeitada sob pdfa1b.
  • 🧯 PDFNATIVE_MCP_MAX_INFLATE_BYTES — substituição pelo operador do limite de descompressão de 100 MiB por fluxo do mecanismo (inteiro ≥ 1024; um valor inválido recusa iniciar). Um fluxo de anexo limitado falha extract_attachments includeData: true com PDF_PARSE_FAILED; extract_text degrada para texto de página vazio (o mecanismo engole falhas de decodificação por página).
  • 📝 Formulários — blocos add_form e formField ganham listbox e placeholder; fieldType: 'textarea' agora chega ao mecanismo como multilineText (antes era passado sem mapeamento e renderizado como um campo de linha única — uma correção de bug que muda bytes para essa entrada). embed_image ganha align e alt.
  • 🔏 Escada de validação de longo prazo PAdES — sign_pdf ganha profile: 'pades' (ETSI EN 319 142-1 baseline, ESS signing-certificate-v2, ETSI.CAdES.detached), timestamp: true (B-T, RFC 3161), RSA-SHA384/512, certChainDerBase64, fieldName / allowMultiple para várias assinaturas; novo add_ltv incorpora um /DSS (B-LT, mode: 'online' através do provedor do operador ou mode: 'offline' com material DER fornecido pelo chamador); novo timestamp_pdf anexa um /DocTimeStamp (B-LTA). verify_pdf ltv: true relata perfil, carimbo de tempo, status de revogação e ltvLevel. Veja docs/guides/LTV.md.
  • 🌐 Carta de rede — nenhuma solicitação de saída por padrão. O único egresso que o servidor pode realizar vai para os endpoints RFC 3161 / OCSP / CRL que o operador configurou (PDFNATIVE_MCP_TSA_URL, PDFNATIVE_MCP_REVOCATION, PDFNATIVE_MCP_NETWORK_ALLOWED_HOSTS), atrás de uma proteção SSRF; argumentos de ferramenta nunca podem fornecer uma URL.
  • 🖨️ Produção de impressão — toda ferramenta de documento aceita print (TrimBox / BleedBox / ArtBox / CropBox ou a abreviação bleed, recorte + marcas de registro marks, /UserUnit), metadata (/Author, /Subject, /Keywords, /Trapped) e outputIntent (ICC RGB personalizado para PDF/A); viewerPreferences ganha duplex, pickTrayByPDFSize, printPageRange, numCopies. inspect_pdf pages: true relata as caixas; mesclar / dividir / extrair as preservam. Veja docs/guides/PRINT.md.
  • ✍️ update_metadata — reescreve /Info + XMP de um PDF existente como uma atualização incremental (revisões anteriores e assinaturas preservadas verbatim).
  • 📊 Gráficos v2 — stackedBar / stackedBarH / area / scatter, eixo direito secundário (axis2), axis.scale: 'log', xAxis.type: 'linear' | 'time', dataLabels, labelStride / labelRotation; rótulos de categoria sobrepostos são reduzidos automaticamente.
  • 📜 PDF/A honesto — embedFonts: true incorpora Noto Sans Latin (Helvetica base-14 não é incorporada, então uma alegação de PDF/A em texto latino simples é rejeitada pelo veraPDF), strict: true falha em vez de produzir um arquivo não conforme, includeDiagnostics: true ecoa diagnósticos do mecanismo. Script local veraPDF (npm run validate:pdfa) sobre um corpus de 26 arquivos (24 validados, 3 deles canários negativos; 2 saídas de árvore de páginas ignoradas) e um modo VERAPDF_REQUIRED=1 com falha fechada; o fluxo de trabalho CI fixa o instalador por SHA-256 e permanece não bloqueante na 1.6.0 (bloqueante desde a v1.7.0, onde --require-all no portão substitui VERAPDF_REQUIRED=1). Lacunas conhecidas do mecanismo na 1.6.0: saída add_form falha PDF/A-2b mesmo com embedFonts (/DR /Helv não incorporado — corrigido na v1.7.0), e uma saída prepare_signature_placeholder é conforme apenas uma vez assinada.
  • 🧰 inspect_pdf — inventário signatures: true, dss / docTimestampCount / trapped (com portão de presença), novos valores check dss, docTimestamp, trapped; checks lista apenas as chaves que você solicitou, e signed é estrutural (um campo assinado existe — validade é trabalho de verify_pdf).
  • 🔁 Saída reproduzível — creationDate opcional em todas as nove ferramentas de documento fixa /CreationDate, as datas XMP e o /ID do trailer; signingTime em prepare_signature_placeholder (e em sign_pdf, agora com deslocamentos de fuso horário) fixa /Sig /M. Bytes idênticos no mesmo fuso horário do host na 1.6.0 (em todo host desde a v1.7.0: datas escritas em UTC). Apoiado pelo prompt reproducible_output.
  • 🛡️ Limite endurecido — esquemas de entrada estritos (chaves desconhecidas ou com erro de digitação → VALIDATION_ERROR em vez de serem ignoradas silenciosamente); prefixos data:…;base64, tolerados, cargas PEM-onde-DER e duplamente codificadas rejeitadas com a solução exata; erros de índice de página nas ferramentas de árvore de páginas são VALIDATION_ERROR com uma dica baseada em 0; um nome de ferramenta desconhecido é um erro de protocolo JSON-RPC (-32602, [UNKNOWN_TOOL]).
  • 🔑 Token de portador HTTP — PDFNATIVE_MCP_HTTP_TOKEN opcional protege o endpoint HTTP Streamable (401 + WWW-Authenticate caso contrário). Sem ele, o endpoint de loopback não tem autenticação — veja SECURITY.md.
  • 🧾 Catálogo — tools/list é ≈ 245 kB (1.5.0: ≈ 108 kB) porque cada tipo de bloco, opção de layout e fragmento encrypt agora é anunciado inline — sem $ref / $defs por política, então hosts que encaminham inputSchema para APIs de chamada de função nunca encontram uma referência; as instruções do servidor são ≈ 6,7 kB (de 12,9 kB). A estrutura é protegida por scripts/tool-shape.mjs (scripts/tool-shape.ts desde a v1.7.0) + tests/catalogue-parity.test.ts, e tests/catalogue-superset.test.ts prova que o catálogo ao vivo é um superconjunto do publicado na 1.5.0; no máximo dois _meta.examples executáveis por ferramenta, o resto sob examples/. Quatro novos prompts de receita: pades_ladder, print_ready, reproducible_output, pdfa_valid.
  • 🐛 Correções — metadados do signatário (signerName / reason / location / contactInfo) nunca alcançavam o dicionário /Sig no pdfnative < 1.7; agora são gravados no momento do placeholder. verify_pdf não relata mais allValid: false em documentos B-LTA (um /DocTimeStamp era analisado como uma assinatura CMS).
  • 🔌 MCP 2026-07-28 no SDK TypeScript MCP v2 (@modelcontextprotocol/server) com fallback automático para o handshake initialize da era 2025 — hosts existentes continuam funcionando sem alterações. Veja conformidade com o protocolo MCP.
  • ⬆ Atualização do mecanismo — pdfnative v1.7.0 (LTV, produção de impressão, gráficos v2, agilidade de digest, sequências de emoji com bandeira / ZWJ, correções UAX #9).

Novo na v1.5.0:

  • 📊 Gráficos vetoriais nativos — add_chart renderiza gráficos de barras / barras horizontais / linhas / pizza / rosca como operadores de caminho PDF puros (zero rasterização, seguro para PDF/A com texto alternativo automático). generate_basic_pdf também aceita um bloco chart para composição com texto e tabelas.
  • 📝 Preencher e achatar formulários — read_form_fields lista os campos de um AcroForm existente; fill_form preenche e/ou achata via uma atualização incremental não destrutiva (a contraparte de add_form).
  • 🔐 Criptografia de ida e volta — encrypt_pdf re-protege com AES-128 / AES-256 (RC4 nunca emitido), decrypt_pdf recupera uma cópia não criptografada, uma entrada password abre fontes criptografadas nas ferramentas somente leitura, e merge_pdfs / split_pdf / extract_pages ganham password + encrypt.
  • 🔤 Extração de texto real — extract_text agora resolve o CMap /ToUnicode de cada fonte (sem mais saída de índice de glifo) e pode retornar runs posicionados.
  • 🔗 Recursos MCP nativos — PDFs gerados em sandbox tornam-se recursos pdfnative://output/… (resources/list + resources/read), com um resource_link em resultados de modo de arquivo para referência cruzada entre chamadas.
  • 🏷️ Anotações de ferramenta — toda ferramenta anuncia readOnlyHint / destructiveHint / idempotentHint / openWorldHint.
  • ⬆ Atualização do mecanismo — pdfnative v1.6.0 (descriptografar/re-criptografar, extractText, preencher/achatar, gráficos; subconjunto de emoji colorido 221 → 1167 glifos).

Novo na v1.4.0:

  • 🤝 Governança de IA + humano no circuito — draft_governance_issue permite que um agente elabore uma issue do GitHub totalmente compatível localmente (rascunho .md + relatório de conformidade legível por máquina). O agente é um redator, nunca um submissor autônomo: um humano é o único portão, e o servidor faz zero gravações no GitHub (e, desde a v1.6.0, nenhuma chamada de saída além dos endpoints TSA / OCSP / CRL configurados pelo operador). Com suporte dos prompts MCP governance_contract e draft_issue_workflow.
  • ✏️ Anotações de marcação — annotate_pdf sobrepõe anotações de destaque, nota adesiva, sublinhado, tachado, ondulado, quadrado, círculo, linha e texto livre em um PDF existente via atualização incremental. É uma camada de revisão visual, não uma redação — os bytes subjacentes permanecem.
  • 🔢 Rótulos de página em inspect_pdf — exibição somente leitura de intervalos /PageLabels (romano, decimal, prefixado).
  • ∑ Script matemático / científico — add_international_text aceita lang: 'math' (explícito, como emoji) para incorporar a fonte Noto Sans Math sob demanda.
  • 🧩 Prompts MCP — o servidor agora anuncia o recurso prompts com governance_contract e draft_issue_workflow.
  • ⬆ Atualização do mecanismo — pdfnative v1.5.0.

Novidades na v1.3.0:

  • 🆕 Três ferramentas de árvore de páginas — merge_pdfs, split_pdf, extract_pages (baseadas na API de árvore de páginas do pdfnative v1.4.0; fontes criptografadas foram rejeitadas até a v1.5.0 adicionar password).

  • 🔖 Favoritos, rótulos de página e listas aninhadas — generate_basic_pdf ganha outline ('auto' ou árvore explícita), pageLabels, itens de lista list multinível e viewerPreferences.

  • 📐 Bordas e alinhamento de células de tabela — add_table ganha cellBorders, cellVAlign e viewerPreferences; add_international_text ganha viewerPreferences.

  • 🔐 Assinatura em tempo constante — sign_pdf assina chaves RSA e EC-DER por meio de um provedor node:crypto com fallback transparente em JS puro (escalares P-256 brutos permanecem em JS puro, e a verificação é em JS puro); as assinaturas permanecem interoperáveis.

  • ⬆ Atualização do mecanismo — pdfnative v1.4.0.

  • 🆕 Ferramenta extract_attachments — lê arquivos incorporados de volta de um PDF (completa o ciclo Factur-X / ZUGFeRD) com payloads byte a byte, um filtro filename e uma sonda somente de metadados includeData: false.

  • 💧 Marcas d'água — generate_basic_pdf e add_table aceitam um watermark opcional (texto, opacidade, ângulo, cor, posição; image desde a v1.6.0) renderizado em todas as páginas.

  • 🌐 Unicode normalize — NFC/NFD/NFKC/NFKD opcionais em generate_basic_pdf e add_international_text.

  • 🪙 Leituras econômicas em tokens — as ferramentas somente leitura (inspect_pdf, verify_pdf, validate_pdf, extract_text, extract_attachments; read_form_fields desde a v1.5.0) aceitam entradas opcionais verbosity: 'summary' e fields: […] para respostas ~90% menores em resultados grandes, sem perda dos campos em que os agentes se baseiam. Os padrões permanecem inalterados.

  • 🪙 Sem duplicação de base64 — PDFs gerados (modo base64) são retornados uma vez como um bloco de conteúdo resource incorporado, em vez de também serem copiados para structuredContent.

  • 🔧 Correção de publicação no registro MCP — mcpName agora usa a grafia canônica do login do GitHub (io.github.Nizoka/pdfnative-mcp) para que a validação sensível a maiúsculas/minúsculas do registro aceite o pacote npm.

  • ⬆ Dependência — atualizado para zod 4.

Novidades na v1.1.0:

  • 🆕 Ferramenta validate_pdf — verificação de conformidade estrutural PDF/UA (ISO 14289-1) somente leitura.
  • 🆕 Seis novos scripts — Telugu, Sinhala, Tibetano, Khmer, Birmanês, Etíope (24 scripts no total).
  • 🆕 Emoji colorido COLRv1 — emoji colorido nativo com fallback monocromático.
  • 🆕 Sanitizador de novas linhas — \n incorporado em parágrafos divide automaticamente em parágrafos separados (PDF/A seguro).
  • 🆕 Normalização NFC automática para add_international_text.
  • 🛠 Atualização do mecanismo — pdfnative v1.3.0: o sinal de Euro / símbolos CP-1252 agora são extraídos corretamente, e células de tabela quebradas recebem MCIDs únicos por linha (seguro para PDF/UA).

Novidades na v1.0.0:

  • 🆕 Três novas ferramentas: verify_pdf, add_attachment (Factur-X / ZUGFeRD), extract_text.
  • 🆕 Campos de tabela inteligente: wrap, repeatHeader, zebra, caption, minRowHeight, cellPadding.
  • 🆕 inspect_pdf agora relata hasSignaturePlaceholder e resumo por anexo; novos valores check 'placeholder' e 'attachments'.
  • 🆕 Ergonomia de assinatura: sign_pdf aceita chaves ECDSA SEC1 / PKCS#8 DER e injeta automaticamente um espaço reservado /Sig quando ausente (assinatura de qualquer PDF em uma única chamada).
  • 🆕 Cache opcional (PDFNATIVE_MCP_CACHE_DIR): chaveado por SHA-256, TTL de 1 h, LRU de 256 MiB.
  • 🆕 _meta.apiVersion e _meta.examples por ferramenta para descoberta por agentes de IA — veja docs/API_STABILITY.md.
  • 🆕 Guia para agentes de IA: docs/AI_GUIDE.md — árvore de decisão + armadilhas comuns. Veja também o contrato de agente, docs/AGENT_CONTRACT.md (catálogo, árvore de decisão, receitas, tabela de erros); contribuidores e agentes de codificação começam em AGENTS.md.
  • 🆕 Guia de autoria PDF/A: docs/guides/PDFA.md.
  • 🛠 Renomeação de variável de ambiente: PDFNATIVE_MCP_OUTPUT_DIR (era PDFNATIVE_MPC_OUTPUT_DIR; o nome antigo ainda funciona com um aviso de depreciação único).
  • ✅ Agora incluído: merge_pdfs, split_pdf, extract_pages (v1.3.0), annotate_pdf (v1.4.0), as ferramentas add_chart / read_form_fields / fill_form / encrypt_pdf / decrypt_pdf além do ciclo criptografado e recursos MCP nativos (v1.5.0), e add_ltv / timestamp_pdf / update_metadata além de produção de impressão e gráficos v2 (v1.6.0). redact_pdf permanece adiado — pdfnative pode sobrepor/achatar, mas não remover conteúdo de página, e uma "redação" apenas de sobreposição criaria falsa segurança, então intencionalmente não é incluído (rastreado como solicitação de remoção de conteúdo upstream).

Todas as ferramentas suportam dois modos de saída:

  • base64 (padrão) — o PDF gerado é retornado uma vez como um bloco de conteúdo resource incorporado (um URI data:application/pdf;base64,…); structuredContent carrega apenas { mode, sizeBytes } (mais diagnostics[] quando includeDiagnostics: true, e um summary para add_ltv).
  • file — o PDF é gravado em um diretório em sandbox configurado via PDFNATIVE_MCP_OUTPUT_DIR. A saída de arquivo é desabilitada a menos que esta variável seja definida; caminhos absolutos, travessia de caminho, extensões não-.pdf e bytes NUL são todos rejeitados.

Atualizando da v1.1.0: a única mudança de comportamento é que os bytes em modo base64 não são mais duplicados em structuredContent.base64. Leia-os do bloco resource incorporado:

- const base64 = response.structuredContent.base64;   // v1.1.0
+ const block = response.content.find((c) => c.type === 'resource');
+ const base64 = block.resource.blob;                  // v1.2.0

Leituras econômicas em tokens (v1.2.0). As sete ferramentas somente leitura (inspect_pdf, verify_pdf, validate_pdf, extract_text, extract_attachments, read_form_fields, inspect_layout) aceitam duas entradas opcionais:

  • verbosity: 'summary' — retorna um veredito compacto somente com escalares (descarta os arrays pesados / texto completo). Ex.: verify_pdf → { signatureCount, allValid, invalid, summary } (+ ltvLevel com ltv: true); inspect_pdf mantém docTimestampCount / trapped / checksPassed quando presentes.
  • fields: ['a', 'b.c'] — projeta o resultado estruturado para caminhos de ponto nomeados; compõe após verbosity. Caminhos sem correspondência são omitidos e relatados em _meta.unmatchedFields (com _meta.availableFields).

Menor sonda "este PDF está assinado e válido?": { "pdfBase64": "…", "verbosity": "summary", "fields": ["allValid"] }.

Por que pdfnative?

pdfnative-mcp herda todas as garantias do mecanismo subjacente:

  • Zero dependências de runtime no mecanismo — JavaScript puro, sem bindings nativos (este servidor adiciona apenas o SDK MCP e zod: três dependências de runtime no total).
  • Saída compatível com ISO 32000-1 (PDF 1.7).
  • PDF/A-1b/2b/2u/3b, criptografia AES-128/256, AcroForm, assinaturas digitais.
  • 27 scripts Unicode (34 códigos lang incl. latin, emoji, math e os quatro aliases latin) com reordenação BiDi integrada, modelagem posicional árabe, modelagem OpenType tailandês/devanágari/bengali/tâmil.
  • Troca de impressão PDF/X-4, cor DeviceCMYK e tipografia fina (controle de órfãs/viúvas, justificação, espaçamento de pontuação francesa, recursos OpenType).
  • Build ESM com tree-shaking.

🚀 Instalação

# Run directly with npx (recommended for MCP clients)
npx -y pdfnative-mcp

# Or install globally
npm install -g pdfnative-mcp
pdfnative-mcp

Requisitos: Node.js ≥ 22.


⚙️ Configuração

Claude Desktop

Edite ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) ou %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "pdfnative": {
      "command": "npx",
      "args": ["-y", "pdfnative-mcp"],
      "env": {
        "PDFNATIVE_MCP_OUTPUT_DIR": "/Users/you/Documents/mcp-pdfs"
      }
    }
  }
}

Cursor / Continue / Zed / Windsurf / Cline / Roo Code

Qualquer cliente compatível com MCP que suporte servidores stdio funcionará. Use a mesma tríplice command + args + env. Exemplo para Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "pdfnative": {
      "command": "npx",
      "args": ["-y", "pdfnative-mcp"],
      "env": { "PDFNATIVE_MCP_OUTPUT_DIR": "/Users/you/Documents/mcp-pdfs" }
    }
  }
}

Windsurf / Cline / Roo Code usam o mesmo formato dentro de seus respectivos arquivos de configuração MCP.

🌐 Ecossistema de IA e Clientes Suportados

pdfnative-mcp é projetado para ambientes nativos MCP e funciona com clientes que suportam MCP via stdio ou Streamable HTTP.

Compatibilidade verificada pela comunidade inclui:

🔌 Conformidade com o protocolo MCP

Desde a v1.6.0, o servidor é construído no SDK TypeScript MCP v2 (@modelcontextprotocol/server) e fala MCP 2026-07-28:

  • Serviço sem estado — server/discover substitui o handshake de sessão; cada resultado carrega resultType e o envelope _meta serverInfo. Via HTTP, clientes 2026-07-28 enviam cabeçalhos Mcp-Method / Mcp-Name com cada POST /mcp.
  • Dicas de cache — tools/list e prompts/list são public com TTL de 24 h ttlMs, server/discover é public por 1 h, e resources/list / resources/templates/list / resources/read são private com ttlMs: 0 (PDFs gerados são dados de usuário por host).
  • Erros de recurso — um URI de recurso desconhecido é relatado como JSON-RPC -32602 (Invalid params), conforme exige a especificação de 2026-07-28.
  • Fallback legado automático — um cliente que abre com initialize (2025-11-25, 2025-06-18 ou 2025-03-26) é atendido pelo caminho legado do SDK tanto em stdio quanto em HTTP. Nada muda para hosts existentes.
  • HTTP — GET / DELETE /mcp respondem 405 (sem retomabilidade SSE; o servidor é sem estado). O bind de loopback e a proteção Host / Origin permanecem inalterados, e a porta Origin agora deve ser igual à porta do servidor (a verificação do SDK sozinha é agnóstica de porta); PDFNATIVE_MCP_HTTP_TOKEN adiciona um gate de bearer token opt-in (401 + WWW-Authenticate sem ele). Arrays de lote JSON-RPC (2025-03-26) são aceitos via HTTP. Conexões keep-alive não acumulam mais listeners de socket.
  • stdio — como em todas as versões do SDK até hoje, uma solicitação enviada antes de initialize é descartada sem resposta e arrays de lote JSON-RPC não são aceitos em stdio (inalterado desde 1.5.0; nenhum host importante usa lotes).
  • Erros de protocolo — tools/call com um nome de ferramenta desconhecido é um erro JSON-RPC (-32602, [UNKNOWN_TOOL] Unknown tool: …) em vez de um resultado isError, conforme a especificação classifica; isError: true é reservado para falhas de execução.
  • Schemas de saída — cada structuredContent valida contra o outputSchema da ferramenta (um MUST de 2026-07-28), incluindo projeções verbosity: 'summary' e fields: as sete ferramentas de leitura declaram schemas projetáveis (todas as propriedades opcionais, additionalProperties: false mantido). Schemas de entrada não carregam a palavra-chave $schema por política (MCP ≥ 2025-11-25 usa por padrão JSON Schema 2020-12; alguns hosts encaminham inputSchema para APIs de function-calling que rejeitam palavras-chave desconhecidas). serverInfo carrega websiteUrl; o template de recurso é pdfnative://output/{+path}.

O payload tools/call (content, structuredContent, isError) é idêntico entre o caminho 2026-07-28 e o caminho legado; tests/http-modern.test.ts o afirma, e tests/schema-conformance.test.ts valida structuredContent com o validador JSON Schema 2020-12 do SDK.

ClienteTransporteProtocolo negociado
Claude Desktop, Cursor, Continue, Zed, Windsurf, Clinestdiolegado initialize (2025-xx) — inalterado
ChatGPT e outros hosts Streamable HTTPHTTP POST /mcpstreamable HTTP legado sem estado — inalterado
Clientes MCP 2026-07-28 (SDK v2 Client, MCP Inspector atual)stdio / HTTPserver/discover, dicas de cache, envelope _meta
Ontheiastdiolegado initialize (verificado pela comunidade, #41)

Variáveis de ambiente

VariávelFinalidade
PDFNATIVE_MCP_OUTPUT_DIRCaminho absoluto para o diretório de sandbox. Obrigatório para habilitar outputMode: 'file'.
PDFNATIVE_MCP_CACHE_DIRCaminho absoluto para habilitar o cache de resultados persistente com chave SHA-256 (TTL de 1 h, LRU de 256 MiB; chave com namespace por API da ferramenta + versão do pacote + o instante de criação fixado). Quando não definido, o cache é desabilitado. Nunca armazena em cache encrypt_pdf / decrypt_pdf / sign_pdf / add_ltv / timestamp_pdf / update_metadata ou chamadas de modo de arquivo; um hit carrega _meta.cached: true e retorna os bytes da chamada anterior.
PDFNATIVE_MCP_PORTQuando definido para uma porta válida (1–65535), inicia um servidor HTTP em http://127.0.0.1:<port>/mcp em vez de stdio. Faz bind apenas em loopback e habilita proteção contra DNS rebinding (Host/Origin estrangeiros → 403). Sem autenticação a menos que PDFNATIVE_MCP_HTTP_TOKEN esteja definido — outros processos locais podem alcançar o endpoint.
PDFNATIVE_MCP_HTTP_TOKEN(v1.6.0, segredo) Bearer token opt-in para o transporte HTTP (≥ 16 caracteres, sem espaços em branco — um valor mais fraco aborta a inicialização). Quando definido, toda solicitação /mcp deve carregar Authorization: Bearer <token>; caso contrário, 401 + WWW-Authenticate: Bearer realm="pdfnative-mcp" (com error="invalid_token" somente quando credenciais foram enviadas — RFC 6750 §3.1). Comparado em tempo constante, nunca registrado em log.
PDFNATIVE_MCP_MAX_INFLATE_BYTES(v1.6.0) Substitui o limite de descompressão de 100 MiB por stream do mecanismo (proteção contra zip-bomb): um número inteiro positivo de bytes ≥ 1024, lido uma vez na inicialização — um valor inválido recusa iniciar. Reduza em um host compartilhado, aumente para arquivos confiáveis de grandes digitalizações. Um stream de anexo limitado falha extract_attachments includeData: true com PDF_PARSE_FAILED; extract_text degrada para texto de página vazio para um stream de conteúdo limitado (comportamento do mecanismo, nenhum erro exibido).
PDFNATIVE_MCP_TSA_URL(v1.6.0) URL absoluta http(s) da autoridade de timestamp RFC 3161 usada por sign_pdf timestamp: true e timestamp_pdf. Não definido: TSA_NOT_CONFIGURED, nenhuma solicitação é feita.
PDFNATIVE_MCP_TSA_AUTH(v1.6.0, segredo) Valor opcional do cabeçalho Authorization enviado ao TSA. Nunca registrado em log ou ecoado.
PDFNATIVE_MCP_REVOCATION(v1.6.0) ocsp, crl ou ocsp,crl — habilita coleta de revogação online para add_ltv mode: 'online'. Não definido: REVOCATION_NOT_CONFIGURED.
PDFNATIVE_MCP_NETWORK_ALLOWED_HOSTS(v1.6.0) Lista de permissões separada por vírgulas (host, host:port, *.suffix) para respondedores OCSP / CRL. Obrigatória quando PDFNATIVE_MCP_REVOCATION está definido — URLs de respondedores vêm de certificados não confiáveis.
PDFNATIVE_MCP_NETWORK_TIMEOUT_MS(v1.6.0) Timeout por solicitação para chamadas TSA / OCSP / CRL, 1000–120000 ms (padrão 10000).
PDFNATIVE_MCP_CREATION_DATE(v1.7.0) Instante ISO 8601 com fuso horário (ex.: 2026-01-01T00:00:00Z) que fixa o instante de criação de todo documento que o processo constrói: /CreationDate, as datas XMP, o /ID do trailer e o placeholder de cabeçalho / rodapé {date}. Lido uma vez na inicialização — um valor inválido recusa iniciar; a fonte da fixação é registrada em stderr.
SOURCE_DATE_EPOCH(v1.7.0) A convenção reproducible-builds.org: segundos inteiros desde a época Unix, usados quando PDFNATIVE_MCP_CREATION_DATE não está definido. Um valor inválido recusa iniciar. Muitos ambientes de build já o exportam: a partir desta versão, ele fixa a data de criação de todo documento — desdefina-o para o processo do servidor se isso não for desejado.

Precedência da data de criação (maior primeiro): o creationDate por chamada → PDFNATIVE_MCP_CREATION_DATE → SOURCE_DATE_EPOCH → o relógio de parede. As datas são sempre escritas em UTC, então a saída fixada é byte-idêntica em todo host e em todo fuso horário. A fixação não cobre, por design: signingTime (sign_pdf, prepare_signature_placeholder), modDate (update_metadata), o segundo /ID regenerado de escritores incrementais (annotate_pdf, fill_form), tokens de timestamp RFC 3161 e dados de revogação online, criptografia (nova chave de arquivo, salts e IVs) e assinaturas ECDSA (randomizadas por design). Veja docs/guides/REPRODUCIBLE.md.


🛠 Referência de ferramentas

generate_basic_pdf

{
  "title": "Q1 2026 Report",
  "blocks": [
    { "type": "heading", "text": "Executive summary", "level": 1 },
    { "type": "paragraph", "text": "Revenue grew 24% year over year." },
    { "type": "list", "style": "bullet", "items": ["Strong APAC", "Stable EU", "Soft NA"] },
    { "type": "pageBreak" },
    { "type": "heading", "text": "Details", "level": 2 }
  ],
  "footerText": "Confidential — Internal use only",
  "outputMode": "base64"
}

Os 13 tipos de bloco: heading, paragraph, list, table, image, link, toc, barcode, svg, formField, chart, pageBreak, spacer. Um relatório composto:

{
  "title": "Quarterly report",
  "blocks": [
    { "type": "toc" },
    { "type": "heading", "text": "Sales", "level": 1 },
    { "type": "table", "headers": ["Region", "Revenue"], "rows": [["EMEA", "1.2 M"], ["APAC", "0.9 M"]], "zebra": true },
    { "type": "image", "imageBase64": "<base64 JPEG>", "mimeType": "image/jpeg", "width": 300, "alt": "Revenue chart" },
    { "type": "svg", "data": "M10 10 H 90 V 90 H 10 Z", "viewBox": [0, 0, 100, 100], "fill": "#0a7e8c" },
    { "type": "barcode", "format": "qr", "data": "https://example.com/q1", "align": "center" },
    { "type": "link", "text": "Full dataset", "url": "https://example.com/data" },
    { "type": "formField", "fieldType": "text", "name": "reviewer", "label": "Reviewed by" }
  ],
  "outline": "auto",
  "pageSize": "Letter",
  "headerTemplate": { "right": "{title} — page {page}/{pages}" },
  "embedFonts": true
}

Regras de bloco: table, barcode, formField e chart aceitam o mesmo corpo que add_table / add_barcode / add_form / add_chart; URLs link devem ser http:, https: ou mailto:; blocos image são limitados a 12 M caracteres base64 cada e 24 MiB decodificados por chamada (PNG: 8-bit grayscale/RGB, não entrelaçado, sem alpha, sem paleta — caso contrário VALIDATION_ERROR com uma solução); svg suporta <path>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <text>/<tspan> e ignora silenciosamente transform, <g>, <use>, <image>, gradientes, opacidade e CSS (nenhuma referência externa é jamais buscada); toc é construído a partir dos blocos de cabeçalho e emparelha com outline: 'auto'; formField sob pdfA precisa de embedFonts: true para que a fonte do campo também seja incorporada (PDFA_UNEMBEDDED_FORM_FONT caso contrário; strict: true então falha); barcode não tem alt. Use inspect_layout com as mesmas entradas para pré-visualizar a paginação antes de renderizar.

Tipografia (v1.7.0). typography é um objeto opt-in (12 chaves, todas desligadas por padrão — omitido significa bytes inalterados) nas nove ferramentas de documento e em inspect_layout:

{
  "title": "Annual report",
  "embedFonts": true,
  "typography": {
    "splitParagraphs": true, "orphans": 3, "widows": 3,
    "keepHeadingsWithNext": { "minLines": 3 },
    "opticalMargins": true, "kerning": true, "fontFeatures": ["onum", "smcp"],
    "unitBinding": true, "bindShortWords": true, "punctuationSpacing": "fr"
  },
  "blocks": [
    { "type": "heading", "text": "Outlook", "level": 2, "keepWithNext": true },
    { "type": "paragraph", "text": "A long justified paragraph…", "align": "justify" },
    { "type": "paragraph", "text": "Figures by region:", "keepWithNext": true, "splittable": false }
  ]
}
  • Chaves: splitParagraphs, orphans / widows (1–10, padrão 2, precisam de splitParagraphs), keepHeadingsWithNext (true ou { minLines }), unitBinding (true ou { units }), bindShortWords (true ou { maxLength, words }), punctuationSpacing ('fr', 'fr-CA' ou um array de regras { char, side, space }), opticalMargins, metrics (padrão 'approximate' / 'exact'), fontFeatures (tnum, pnum, lnum, onum, zero, ordn, sups, subs, smcp, c2sc, case), kerning, hyphenationLanguage.
  • Entradas de bloco: um paragraph aceita align (padrão left / right / center / justify), keepWithNext e splittable (substitui typography.splitParagraphs para aquele bloco); um heading aceita keepWithNext (substitui typography.keepHeadingsWithNext para aquele bloco).
  • Limites: kerning, fontFeatures e o espaço no-break estreito 'fr' precisam de uma fonte incorporada (embedFonts: true; na Helvetica base-14 'fr' degrada para 'fr-CA'); metrics: 'exact' atua apenas em texto base-14; tnum / lnum não mudam nada no Noto Sans incluído (TYPOGRAPHY_FEATURE_INEFFECTIVE de diagnóstico); nenhum dicionário de hifenização está instalado, então hyphenationLanguage não tem efeito neste servidor — hifens suaves (U+00AD) no texto são respeitados. Veja docs/guides/TYPOGRAPHY.md e o prompt typography. Cores CMYK (v1.7.0). Cada entrada de cor mantém a forma que sempre aceitou (hex em gráficos, modelos, blocos link e svg; um trio RGB 0–1 em marcas d'água e annotate_pdf; uma string livre em entradas de contorno e bordas de células de tabela) e ganha DeviceCMYK ao lado: uma string de operando 'c m y k' com componentes 0–1 ("1 0.6 0 0.1") e uma tupla percentual [c, m, y, k] com componentes 0–100 ([100, 60, 0, 10]). Sob uma declaração PDF/A contra a intenção sRGB padrão, uma cor CMYK relata PDFA_DEVICE_CMYK_CONTENT — mantenha as cores RGB lá, ou forneça um outputIntent CMYK.

PDF/X-4 (v1.7.0). pdfx: 'pdfx4' em generate_basic_pdf, add_table, add_chart, add_barcode, embed_image e add_international_text grava um arquivo PDF/X-4 (ISO 15930-7): cabeçalho %PDF-1.6, a identificação XMP PDF/X-4, uma intenção de saída /GTS_PDFX, uma TrimBox em cada página e /Trapped.

{
  "title": "Spring catalogue",
  "pdfx": "pdfx4",
  "embedFonts": true,
  "outputIntent": { "iccProfileBase64": "<the printer's CMYK ICC profile, base64>", "outputConditionIdentifier": "FOGRA39" },
  "metadata": { "trapped": "False" },
  "print": { "bleed": 14.17, "marks": { "colourBars": true } },
  "blocks": [{ "type": "paragraph", "text": "Four-colour job exchanged as PDF/X-4." }]
}
  • Requer outputIntent com o perfil ICC da condição de impressão (classe de dispositivo prtr, CMYK ou Gray — nenhum perfil de impressora é incluído; pergunte à sua gráfica); precisa de embedFonts: true para um arquivo conforme (PDFX_NO_FONT_ENTRIES caso contrário; strict: true recusa); é exclusivo com pdfA e encrypt; metadata.trapped deve ser 'True' ou 'False'; uma página carrega uma TrimBox ou uma ArtBox, não ambas. Solicitações incoerentes são recusadas com VALIDATION_ERROR antes de qualquer trabalho ser feito. Links e campos de formulário são relatados (PDFX_ANNOTATIONS); com strict: true um diagnóstico PDFX_* falha a chamada com PDF_X_COMPLIANCE_VIOLATION.
  • outputIntent aceita perfis RGB, CMYK e Gray (≤ 8 MiB, sob pdfA ou pdfx). O perfil deve ser um arquivo ICC real (assinatura acsp, campo de tamanho consistente) — um stub feito à mão é rejeitado.
  • print.marks aceita true ou um objeto; marks.colourBars (true ou { tints, size }, size 4–72 pt, padrão 12) adiciona os sólidos C M Y K e seus tons de 50 % no sangramento. Desativado por padrão; precisa de um sangramento de cerca de 5 mm (14,17 pt) e é ignorado quando a faixa não caberia.
  • Verifique o resultado com validate_pdf { standard: 'pdf-x-4' } — uma verificação estrutural, não um preflight certificado. Veja docs/guides/PRINT.md e o prompt print_ready.

add_barcode

{
  "format": "qr",
  "data": "https://pdfnative.dev",
  "caption": "Scan to learn more",
  "ecLevel": "H",
  "outputMode": "file",
  "outputPath": "tickets/event-42.pdf"
}

Formatos suportados: qr, code128, ean13, datamatrix, pdf417.

add_international_text

{
  "title": "مرحبا بالعالم",
  "lang": "ar",
  "paragraphs": [
    "هذا اختبار للنص العربي مع تشكيل OpenType ومحارف ثنائية الاتجاه.",
    "Mixed content: العربية + English ✓"
  ]
}

Códigos lang suportados: os 27 scripts Unicode — ar, he, th, ja, zh, ko, el, hi, bn, ta, ru, ka, hy, tr, pl, vi, te, si, bo, km, my, am, e desde v1.7.0 lo (Lao), nod (Tai Tham), khb (New Tai Lue), tdd (Tai Le), cjm (Cham) — mais as faces utilitárias latin, emoji e math. Desde v1.7.0 ha (Hausa), yo (Yoruba), ig (Igbo) e sw (Suaíli) são aliases de latin: o Noto Sans incluído ancora suas marcas de tom, nenhuma fonte extra é incorporada. Fontes são sempre incorporadas (sem entrada embedFonts); fixe creationDate para saída byte-idêntica. A ferramenta também aceita typography e pdfx (veja generate_basic_pdf).

Tai Tham sob PDF/A: use pdfA: 'pdfa2b' com lang: 'nod', não pdfa2u — um glifo carece de uma entrada ToUnicode no mecanismo, que o veraPDF rejeita sob PDF/A-2u (rastreado upstream).

Documentos multi-script — passe um array ou lista separada por vírgulas:

{
  "title": "Mixed Script",
  "lang": ["ar", "emoji"],
  "paragraphs": ["العربية مع رموز 🎉🚀"],
  "pdfA": "pdfa2u"
}

sign_pdf

A partir de v1.0.0, sign_pdf injeta automaticamente um placeholder /Sig quando ausente — você pode assinar qualquer PDF em uma chamada:

{
  "pdfBase64": "<any base64 PDF>",
  "algorithm": "rsa-sha256",
  "certDerBase64": "<base64 X.509 cert in DER>",
  "rsaKeyPkcs1DerBase64": "<base64 PKCS#1 RSAPrivateKey DER>",
  "signerName": "Alice",
  "reason": "Approval",
  "location": "Paris, FR",
  "signingTime": "2026-01-15T10:30:00Z"
}

Para ECDSA P-256: use algorithm: "ecdsa-sha256" e forneça ecPrivateKeyDerBase64 (SEC1 ou PKCS#8 DER) ou ecPrivateScalarHex (64 caracteres hex).

Conversão PEM → DER:

openssl x509 -in cert.pem -outform DER | openssl base64 -A                 # cert
openssl rsa  -in key.pem  -outform DER -traditional | openssl base64 -A    # RSA PKCS#1
openssl pkey -in key.pem  -outform DER | openssl base64 -A                 # ECDSA

Use prepare_signature_placeholder apenas quando precisar personalizar o placeholder (por exemplo, placeholderBytes maior para chaves RSA >4096 bits, subFilter: 'ETSI.CAdES.detached', reserveTimestamp: true). Caso contrário, chame sign_pdf diretamente.

Escada PAdES (v1.6.0). sign_pdf com profile: "pades" produz uma assinatura B-B; adicione timestamp: true para B-T (precisa de PDFNATIVE_MCP_TSA_URL), depois add_ltv (B-LT) e timestamp_pdf (B-LTA):

// 1. sign_pdf  { ..., "profile": "pades", "timestamp": true, "certChainDerBase64": ["<intermediate DER>"] }
// 2. add_ltv   { "pdfBase64": "<signed>", "mode": "online" }            // or "offline" + certificatesDerBase64 / ocspResponsesDerBase64 / crlsDerBase64
// 3. timestamp_pdf { "pdfBase64": "<ltv>" }                              // re-run before the TSA certificate expires
// 4. verify_pdf { "pdfBase64": "<final>", "ltv": true }                  // -> ltvLevel: "B-LTA"

Metadados do signatário (signerName, reason, location, contactInfo) são gravados no placeholder; fieldName seleciona um de vários placeholders não assinados (PLACEHOLDER_AMBIGUOUS caso contrário) e allowMultiple: true adiciona uma assinatura adicional. Veja docs/guides/LTV.md.


add_table

{
  "title": "Monthly Sales",
  "headers": ["Region", "Units", "Revenue"],
  "rows": [
    ["APAC", "1200", "$240,000"],
    ["EMEA", "800", "$160,000"]
  ],
  "infoItems": [{ "label": "Period", "value": "January 2025" }],
  "footerText": "Internal use only",
  "outputMode": "base64"
}

add_form

{
  "title": "Employee Onboarding",
  "fields": [
    { "fieldType": "text", "name": "fullName", "label": "Full Name", "required": true },
    { "fieldType": "dropdown", "name": "dept", "label": "Department", "options": ["Engineering", "Sales", "HR"] },
    { "fieldType": "checkbox", "name": "agree", "label": "I agree to the terms", "checked": false },
    { "fieldType": "listbox", "name": "skills", "label": "Skills", "options": ["TypeScript", "PDF", "MCP"] },
    { "fieldType": "textarea", "name": "notes", "label": "Notes", "placeholder": "Anything we should know?" }
  ],
  "outputMode": "base64"
}

Tipos de campo: text, textarea (multilinha, /Ff 4096), checkbox, radio, dropdown, listbox; placeholder mostra texto de dica enquanto um campo está vazio. Adicione encrypt para produzir um formulário protegido por senha que mantém seu AcroForm. Sob uma declaração PDF/A, passe embedFonts: true para que a fonte do campo também seja incorporada (desde v1.7.0 tal formulário valida sob veraPDF); sem isso, a chamada relata PDFA_UNEMBEDDED_FORM_FONT (strict: true então falha).

embed_image

{
  "title": "Product Photo",
  "imageBase64": "<base64-encoded JPEG bytes>",
  "mimeType": "image/jpeg",
  "caption": "Front view of Model X",
  "width": 400,
  "align": "center",
  "alt": "Front view of the Model X chassis",
  "outputMode": "base64"
}

Nota: o decodificador PNG do mecanismo aceita apenas imagens de 8 bits, não entrelaçadas, em escala de cinza / RGB. Canais alfa (tipo de cor 4 / 6), paleta (tipo 3), PNGs de 16 bits e entrelaçados são rejeitados no limite com VALIDATION_ERROR e uma solução (achatar ou reexportar) — a mesma regra se aplica a blocos image e marcas d'água de imagem. embed_image.imageBase64 mantém seu contrato 1.5.0 sem limite de comprimento; o limite de 12 M caracteres se aplica apenas a blocos image inline e imagens de marca d'água.

prepare_signature_placeholder

{
  "title": "Service Agreement",
  "signerName": "Alice Dupont",
  "reason": "Approved",
  "location": "Paris, FR",
  "blocks": [
    { "type": "paragraph", "text": "By signing below, I accept the terms and conditions." }
  ],
  "outputMode": "base64"
}

Passe os bytes PDF retornados para sign_pdf para concluir o fluxo de assinatura.

inspect_pdf

Inspeção estrutural e de segurança somente leitura — útil para verificação downstream, asserções de CI e agentes de IA que precisam raciocinar sobre um PDF antes de agir sobre ele.

{
  "pdfBase64": "<base64 PDF>",
  "pages": true,
  "check": ["pdfa", "signed", "attachments"]
}

Retorna:

{
  "version": "1.7",
  "pageCount": 3,
  "encryption": "none",          // 'none' | 'aes-128' | 'aes-256' | 'rc4' | 'unknown'
  "pdfA": "3B",                  // null when no PDF/A claim is present
  "signatureCount": 1,
  "hasSignaturePlaceholder": false,
  "attachments": [{ "filename": "factur-x.xml", "mimeType": "application/xml", "sizeBytes": 1234, "relationship": "Source" }],
  "info": { "Producer": "pdfnative", "Title": "Invoice INV-2025-001" },
  "perPage": [{ "index": 0, "width": 595, "height": 842 }],
  "checks": { "pdfa": true, "signed": true, "attachments": true },
  "checksPassed": true
}

check[] aceita qualquer um de 'pdfa', 'signed', 'encrypted', 'placeholder', 'attachments', 'dss', 'docTimestamp', 'trapped', 'annotations' (os últimos quatro desde v1.6.0) e 'pdfx' (desde v1.7.0: o XMP declara PDF/X — a declaração, não sua validade; isso é validate_pdf standard: 'pdf-x-4'). pdfX aparece no resultado apenas quando o XMP declara PDF/X (mantido por verbosity: 'summary'). checksPassed é o E de todas as verificações solicitadas. signatures: true adiciona um inventário por campo (subFilter, isDocTimestamp, isPlaceholder, byteRange, vriKey); annotations: true adiciona annotations[] (cada entrada /Annots: page baseado em 0, subtype, rect, e quando presente contents truncado para 200 caracteres, title, color, quadPoints, link url) mais annotationCount; dss, docTimestampCount e trapped aparecem apenas quando presentes; com pages: true cada entrada perPage também carrega trimBox / bleedBox / artBox / cropBox / userUnit quando definidos.

inspect_layout

Simulação de paginação somente leitura — o mesmo blocks que generate_basic_pdf mais cada entrada que move um bloco (title, footerText, pdfA, normalize, embedFonts, pageSize, margins, headerTemplate, footerTemplate, e desde v1.7.0 typography). Nenhum PDF é produzido; passe exatamente o que você dará a generate_basic_pdf e totalPages corresponde.

{ "title": "Memo", "blocks": [{ "type": "paragraph", "text": "Short note." }], "pageSize": "Letter", "verbosity": "summary", "fields": ["totalPages"] }

O resultado completo carrega pageWidth, pageHeight, margins, totalPages e pages[].blocks[] (type, page, x, top, width, height em pontos, arredondados para duas casas decimais). Desde v1.7.0 a simulação e a construção compartilham um planejador de paginação, então cada tipo de bloco — toc incluído — é medido exatamente como é disposto (em 1.6.0 um bloco toc era medido como 0 pt).

validate_pdf

Verificação de conformidade estrutural somente leitura. standard escolhe o conjunto de regras: 'pdf-ua-1' (padrão — PDF/UA, ISO 14289-1, para um PDF marcado) ou, desde v1.7.0, 'pdf-x-4' (PDF/X-4, ISO 15930-7). Gere um documento acessível com qualquer ferramenta usando pdfA (por exemplo, pdfA: 'pdfa2u'), depois valide o resultado:

{ "pdfBase64": "<tagged-pdf-base64>" }

Retorna:

{
  "standard": "pdf-ua-1",
  "valid": true,
  "errors": [],          // blocking structural violations (empty when valid)
  "warnings": [],        // non-blocking best-practice recommendations
  "summary": "PDF/UA structural prerequisites hold."
}

Verifica catálogo /MarkInfo /Marked true, /StructTreeRoot (+ /ParentTree), /Metadata (XMP), /Lang, e unicidade de MCID por página. Esta é uma porta rápida de tempo de desenvolvimento — não um substituto para um validador de referência completo (veraPDF), que adicionalmente verifica fontes, cor e renderização.

PDF/X-4 (v1.7.0). { "pdfBase64": "<pdf>", "standard": "pdf-x-4" } verifica os pré-requisitos estruturais da ISO 15930-7: cabeçalho PDF 1.6, sem criptografia, trailer /ID, a identificação XMP PDF/X-4, uma intenção de saída /GTS_PDFX com um perfil ICC prtr incorporado, uma TrimBox ou ArtBox por página aninhada na BleedBox e MediaBox, toda fonte incorporada, nenhuma anotação na área impressa, nenhum JavaScript, nenhum arquivo incorporado, cor de dispositivo consistente com a intenção de saída. O resultado tem a mesma forma mais caveats[], que declara o que um veredito valid: true não estabelece: isto não é um preflight certificado, e o veraPDF não cobre PDF/X — confirme um trabalho de impressão com callas pdfToolbox ou Acrobat Preflight. A resposta padrão (pdf-ua-1) é inalterada e não carrega caveats.

annotate_pdf

Sobreponha anotações de marcação em um PDF existente via atualização incremental. Esta é uma camada de revisão visual, não uma redação — o conteúdo subjacente é intocado.

{
  "pdfBase64": "<base64 PDF>",
  "annotations": [
    { "type": "highlight", "page": 0, "rect": [72, 700, 520, 715], "color": [1, 1, 0], "contents": "Check this figure" },
    { "type": "text", "page": 0, "rect": [540, 700, 560, 720], "contents": "Reviewer note" }
  ]
}

Tipos: text, highlight, underline, strikeout, squiggly, square, circle, line, freetext. Índices de página são baseados em 0. color / interiorColor aceitam uma string hex ou operando (incluindo uma string de operando CMYK), um trio RGB 0–1 ([1, 1, 0]) ou, desde v1.7.0, uma tupla percentual CMYK ([0, 0, 100, 0]); v1.7.0 também corrige o trio 0–1, que costumava renderizar quase preto. Fontes criptografadas são rejeitadas (ENCRYPTED_SOURCE) — execute decrypt_pdf primeiro (remove assinaturas / AcroForm), anote, depois encrypt_pdf novamente.

draft_governance_issue

Rascunhe uma issue GitHub compatível com governança localmente para um humano revisar e enviar. O servidor nunca contata o GitHub (seu único egresso possível são os endpoints TSA / OCSP / CRL configurados pelo operador — veja Rede e egresso); ele retorna o rascunho em Markdown mais um relatório de conformidade legível por máquina.

{
  "title": "add_table drops the caption on the second page",
  "issueType": "bug",
  "summary": "The table caption is only rendered on page 1 when repeatHeader is true.",
  "reproduction": { "command": "add_table with caption + repeatHeader over 2 pages (examples/bordered-table.json, then inspect_pdf)", "result": "Page 2 has no caption row." },
  "expectedBehavior": "The caption repeats with the header on every page.",
  "duplicateSearchPerformed": true
}

Um rascunho que propõe uma dependência de tempo de execução, omite uma reprodução ou define duplicateSearchPerformed: false é rejeitado com GOVERNANCE_VIOLATION. Veja docs/guides/AI_GOVERNANCE.md para o contrato completo de humano-no-loop.

verify_pdf, add_attachment, extract_text

Veja as seções dedicadas em docs/AI_GUIDE.md e a referência em docs/KNOWLEDGE_BASE.md. Exemplos prontos para execução estão em examples/.


🔐 Modelo de segurança

pdfnative-mcp executa dentro do processo host e expõe um servidor MCP via stdio (ou um endpoint HTTP somente loopback). Ele não realiza nenhuma operação de E/S fora do sandbox configurado.

  • Gravações de arquivos são controladas por PDFNATIVE_MCP_OUTPUT_DIR. Quando não definido, o modo de saída file é rejeitado com um SecurityError.
  • Resolução de caminhos rejeita caminhos absolutos, sequências de travessia (..), bytes NUL e qualquer extensão diferente de .pdf.
  • Tamanho da saída é limitado a 50 MB por chamada.
  • Entradas são validadas contra esquemas JSON estritos + verificações de runtime Zod na fronteira de cada ferramenta — chaves desconhecidas ou com erro de digitação (no nível superior ou aninhadas) são rejeitadas com VALIDATION_ERROR, e cargas base64 / DER passam por verificação de sanidade (prefixo data: tolerado, entrada PEM ou duplamente codificada rejeitada com a correção) antes de qualquer parser ser executado.
  • Transporte HTTP (PDFNATIVE_MCP_PORT) vincula-se apenas a loopback; não possui autenticação a menos que PDFNATIVE_MCP_HTTP_TOKEN esteja definido (então 401 sem um token bearer válido).

Rede e saída de dados

O servidor não faz nenhuma chamada de rede de saída por padrão. A única saída que ele pode realizar vai para os endpoints RFC 3161 / OCSP / CRL que o operador configurou no ambiente para validação de longo prazo PAdES (PDFNATIVE_MCP_TSA_URL, PDFNATIVE_MCP_REVOCATION, PDFNATIVE_MCP_NETWORK_ALLOWED_HOSTS) — nunca para uma URL fornecida por um argumento de ferramenta, nunca para o GitHub, nunca para telemetria. Sem essa configuração sign_pdf timestamp: true, timestamp_pdf e add_ltv mode: 'online' falham rapidamente com TSA_NOT_CONFIGURED / REVOCATION_NOT_CONFIGURED antes de tocar no documento; add_ltv mode: 'offline' incorpora material fornecido pelo chamador com zero acesso à rede.

As URLs de OCSP / CRL vêm das extensões AIA / CRL-distribution-point de certificados não confiáveis dentro do PDF, portanto cada busca passa por uma proteção SSRF:

  • o host deve corresponder à lista de permissões do operador (host, host:port ou *.suffix; curingas simples são rejeitados). As entradas são nomes de host, não URLs: uma entrada host:port só corresponde a URLs com uma porta explícita (o parser de URL descarta as portas padrão :80 / :443 — liste o host simples para essas); entradas curinga não podem ter porta; nomes de host IDN devem ser listados em punycode (xn--…); literais IPv6 entre colchetes ([2001:db8::1]);
  • apenas http: / https:, sem credenciais incorporadas, redirecionamentos nunca são seguidos;
  • literais de endereço loopback, link-local, privado, unique-local, CGNAT, não especificado e multicast (incluindo grafias decimal / octal / hexadecimal e IPv6 mapeado para IPv4) são rejeitados, a menos que esse literal esteja na lista de permissões literalmente. A proteção verifica apenas literais — um nome de host listado que resolve para um endereço interno (DNS rebinding) não é detectado, pois não há resolvedor sem adicionar uma dependência; coloque na lista de permissões apenas hosts que você controla;
  • tempo limite por solicitação (PDFNATIVE_MCP_NETWORK_TIMEOUT_MS) e limites de resposta (256 KiB TSA, 1 MiB OCSP, 16 MiB CRL) aplicados durante o streaming, portanto uma resposta superdimensionada é cortada em vez de armazenada em buffer;
  • respostas OCSP e CRLs retornadas pelos respondedores são validadas por parse antes de add_ltv incorporá-las;
  • a URL do TSA é confiável pelo operador (verificações de esquema + credenciais apenas); o segredo PDFNATIVE_MCP_TSA_AUTH nunca é registrado em log ou ecoado em mensagens de erro.

Os provedores são construídos por chamada e passados pelas opções por chamada do pdfnative — os setters de provedor em todo o processo nunca são usados, portanto solicitações concorrentes não compartilham nada. As instruções server/discover relatam a política de saída atual (apenas tipos de endpoint, nunca segredos).

Veja SECURITY.md para o processo de divulgação responsável e docs/guides/LTV.md para a configuração do operador.


🧪 Desenvolvimento local

git clone https://github.com/Nizoka/pdfnative-mcp.git
cd pdfnative-mcp
npm ci                    # .npmrc sets ignore-scripts=true: nothing builds on install
npm run gate:fast         # before every commit: typecheck:all, lint, test, server-json, verify:docs
npm run gate              # the CI profile: build, dist checks, stdio smoke test, tool shape, samples, coverage, docs, corpus, validate:pdfx
npx tsx scripts/gate.ts --publish --require-all   # release branches: everything incl. validate:pdfa (veraPDF); a skipped step fails

npm run gate (scripts/gate.ts) é a definição única de "verde" — 1631 testes, os limites de cobertura de vitest.config.ts, e o servidor compilado acionado via stdio, onde o stdout deve conter apenas quadros JSON-RPC. Ele imprime uma linha por etapa e grava os logs em test-output/.gate/<step>.log; --only <step> executa uma etapa e --json fornece saída de máquina (chame o script diretamente para passar flags: npx tsx scripts/gate.ts --fast). As etapas individuais são scripts npm comuns:

npm run build && npm run test:generate   # drive the built server under TZ=UTC, operator variables scrubbed -> test-output/samples/
npm run verify:samples    # hold the 96 samples to tests/_fixtures/samples.sha256.json (93 by bytes, 3 by a semantic projection)
npm run corpus:pdfa       # write the 41-file conformance corpus (33 claim PDF/A, 6 claim PDF/X-4, 2 page-tree outputs claim nothing)
npm run validate:pdfx     # in-process structural PDF/X-4 check of the corpus; never skips
npm run validate:pdfa     # veraPDF over the PDF/A files (VERAPDF_HOME, JAVACMD); exit 0 ok / 1 conformance / 2 infrastructure
npm run verify:docs       # every count, version, tool, error code, operator variable, link and anchor in the docs vs docs/assets/ecosystem.json and src/
npx tsx scripts/tool-shape.ts --write   # only after a deliberate tools/list schema change (npm run verify:tool-shape checks the fixture)

Uma mudança de saída pretendida é re-baselined com npx tsx scripts/verify-samples.ts --update e declarada na nota de versão — nunca para silenciar uma surpresa. Com veraPDF 1.30.2, o corpus dá 27 PASS e 6 falhas esperadas (canários negativos que devem permanecer rejeitados). Cada script, suas flags e seus códigos de saída estão listados em scripts/README.md.

Teste o servidor via stdio:

node dist/cli.js
# In another terminal, send a JSON-RPC initialize request via stdin (e.g. with mcp-inspector).

Colaboradores: comece em AGENTS.md (as regras do repositório compartilhadas por todo agente de codificação e colaborador) e veja docs/guides/LOCAL_TESTING.md para o fluxo completo de verificação local — o portão de qualidade, exemplos-como-testes, validação de que PDFs gerados são estruturalmente corretos (assertValidPdf, inspect_pdf, validate_pdf, verify_pdf), abertura de saída em um visualizador, verificação externa de PDF/A com veraPDF e o MCP Inspector.

📣 Processo de lançamento

pdfnative-mcp segue o mesmo formalismo de lançamento que pdfnative:

  • Um arquivo de nota de versão por tag em release-notes/vX.Y.Z.md
  • CHANGELOG.md espelha cada lista de marcadores da versão
  • O corpo da Release do GitHub é copiado de release-notes/vX.Y.Z.md
  • npx tsx scripts/release-prepare.ts --version X.Y.Z aplica a parte mecânica de um incremento de versão (nunca faz commit, tag ou publicação); a versão se move em sincronia em package.json, src/version.ts, server.json e docs/assets/ecosystem.json
  • Uma branch de lançamento deve passar em npx tsx scripts/gate.ts --publish --require-all — cada etapa, incluindo veraPDF, sem pular
  • A publicação no npm é tratada pelo GitHub Actions Trusted Publishing (OIDC), sem NPM_TOKEN, a partir de um ambiente protegido: o workflow verifica se a tag é igual à versão do pacote, executa o portão de publicação e publica com --provenance; um segundo job atesta o tarball (proveniência de build) juntamente com um SBOM CycloneDX e anexa ambos à Release do GitHub
  • Cada job Linux e Windows começa com step-security/harden-runner (a ação não suporta macOS; o job macOS é a exceção documentada), faz checkout com persist-credentials: false, instala com npm ci --ignore-scripts e executa sob permissions de privilégio mínimo; as ações são fixadas por SHA de commit; o job veraPDF é bloqueante
  • Humano no circuito: agentes de codificação preparam e verificam; o mantenedor faz push, abre o pull request, cria a tag e publica (.github/AGENT_RULES.md)

Veja release-notes/TEMPLATE.md para a estrutura canônica e a lista de verificação de publicação, e CONTRIBUTING.md para o procedimento de lançamento.


📚 Estrutura do projeto

src/
├── cli.ts                      # entrypoint: stdio (default) or Streamable HTTP (PDFNATIVE_MCP_PORT)
├── http.ts                     # Node http <-> Web Request/Response bridge + Host/Origin loopback guard
├── auth.ts                     # opt-in HTTP bearer token (PDFNATIVE_MCP_HTTP_TOKEN)
├── base64.ts                   # base64 / DER boundary decoding with agent-facing diagnostics
├── index.ts                    # public library exports
├── server.ts                   # Server factory, tool registry, cache hints, SERVER_INSTRUCTIONS
├── network.ts                  # operator-configured TSA / OCSP / CRL egress + SSRF guard
├── print.ts                    # print-production schema (boxes, bleed, marks + colour bars, userUnit, RGB / CMYK / Gray outputIntent, metadata, creationDate)
├── pdfx.ts                     # pdfx: 'pdfx4' conformance target + the static conflicts refused before the build
├── color.ts                    # shared colour fragment: CMYK operand string / percent tuple beside each historical form, toEngineColor()
├── typography.ts               # the typography fragment (12 opt-in keys) + TypographyOptions mapper
├── reproducible.ts             # operator-pinned creation instant (PDFNATIVE_MCP_CREATION_DATE, SOURCE_DATE_EPOCH)
├── diagnostics.ts              # engine diagnostics sink (PDFA_* / PDFX_* / TYPOGRAPHY_*), strict escalation by code, includeDiagnostics, embedFonts
├── chart.ts                    # charts v2 schema + ChartBlock mapper
├── blocks.ts                   # the 7 extended document blocks (table, image, link, toc, barcode, svg, formField)
├── layout.ts                   # pageSize / margins / header & footer templates / compress / debug / encrypt / typography (PdfLayoutOptions)
├── table.ts, barcode.ts, form.ts, image.ts   # bodies shared by a dedicated tool and its inline block
├── watermark.ts                # text and/or image watermark + position, PDF/A-1b transparency guard
├── encryption.ts               # password + encrypt schema (Standard Security Handler), decrypt error mapping
├── inflate-cap.ts              # PDFNATIVE_MCP_MAX_INFLATE_BYTES (engine decompression cap) + PDF_PARSE_FAILED mapping
├── output.ts                   # sandboxed file writer / base64 emitter (single + multi)
├── text.ts                     # newline sanitizer (Safe PDF/A)
├── doc-features.ts             # nested lists, outline, page labels, viewer prefs (+ print-dialog defaults)
├── pagetree.ts                 # page-tree error mapping (merge/split/extract)
├── crypto-provider.ts          # node:crypto signing provider for DER keys (SHA-256/384/512); verification stays pure JS
├── projection.ts               # verbosity / fields projection for the seven read tools
├── errors.ts                   # ToolError, SecurityError, GovernanceError
└── tools/
    ├── generate-basic-pdf.ts
    ├── inspect-layout.ts
    ├── add-barcode.ts
    ├── sign-pdf.ts
    ├── add-ltv.ts
    ├── timestamp-pdf.ts
    ├── update-metadata.ts
    ├── add-international-text.ts
    ├── add-table.ts
    ├── add-form.ts
    ├── read-form-fields.ts
    ├── fill-form.ts
    ├── add-chart.ts
    ├── embed-image.ts
    ├── inspect-pdf.ts
    ├── verify-pdf.ts
    ├── validate-pdf.ts
    ├── add-attachment.ts
    ├── extract-attachments.ts
    ├── extract-text.ts
    ├── merge-pdfs.ts
    ├── split-pdf.ts
    ├── extract-pages.ts
    ├── annotate-pdf.ts
    ├── encrypt-pdf.ts
    ├── decrypt-pdf.ts
    ├── draft-governance-issue.ts
    └── prepare-signature-placeholder.ts
scripts/                        # TypeScript run by tsx — the full table is in scripts/README.md
├── gate.ts                     # THE quality gate (npm run gate / gate:fast; --publish --require-all on release branches)
├── generate-samples.ts         # npm run test:generate — the built server under TZ=UTC -> test-output/samples/
├── verify-samples.ts           # npm run verify:samples — the byte baseline (tests/_fixtures/samples.sha256.json)
├── generate-pdfa-corpus.ts     # npm run corpus:pdfa — the 41-file PDF/A + PDF/X-4 conformance corpus
├── validate-pdfa.ts            # npm run validate:pdfa — veraPDF (PASS/FAIL/XFAIL/XPASS; exit 0 / 1 / 2)
├── validate-pdfx.ts            # npm run validate:pdfx — in-process structural PDF/X-4 check, never skips
├── tool-shape.ts               # structural tools/list fingerprint (--write refreshes tests/_fixtures/tool-shape.json)
├── verify-docs.ts              # npm run verify:docs — the docs held to docs/assets/ecosystem.json and the source tree
├── release-prepare.ts          # mechanical version bump (never commits, tags or publishes)
├── build-claude-rules.ts       # npm run agents:rules — .github/instructions/ -> .claude/rules/
└── verify-issue.mjs            # governance draft checker (npm run verify:issue)
docs/
├── AGENT_CONTRACT.md           # the consumer contract for agents that USE the server (catalogue, decision tree, recipes, error codes)
├── AI_GUIDE.md, KNOWLEDGE_BASE.md, API_STABILITY.md
├── guides/                     # PDFA, PRINT, TYPOGRAPHY, REPRODUCIBLE, CHARTS, FORMS, ENCRYPTION, LTV, AI_GOVERNANCE, LOCAL_TESTING
└── assets/ecosystem.json       # the single source of every count and version quoted in the docs
examples/                       # 43 executable tools/call sequences (npm run examples:check)
AGENTS.md, CLAUDE.md            # repository rules for coding agents; .github/instructions/ holds the per-area rules
.claude/                        # shared agent settings, the fail-closed guard hook, generated rules, the release-audit skill
.github/workflows/              # ci (Node 22 / 24 on Linux, plus Windows and macOS, all running the gate, all required), publish, sample-regression, verapdf (blocking),
                                #   docs, codeql, scorecard, dependency-review, audit
.github/rulesets/               # branch and tag rulesets to import
tests/                          # vitest suites (one per tool / module), _fixtures/ (tool shape, sample baseline, engine-surface matrix,
                                #   the frozen 1.5.0 catalogue), tools/ (repository tooling)

🗺 Roteiro

A v1.7.0 foi lançada (tipografia fina, cores CMYK, PDF/X-4, 27 scripts Unicode, saída reproduzível em todos os hosts, pdfnative 1.8), sobre a v1.6.0 (cobertura completa do motor — 13 tipos de bloco, opções de layout, inspect_layout — escada PAdES LTV, produção gráfica, gráficos v2, update_metadata, MCP 2026-07-28). O plano completo — marcos lançados, trabalho em andamento e direção de longo prazo — está em ROADMAP.md.

Ainda adiado:

  • redact_pdf — pdfnative não tem API de remoção de conteúdo; uma "redação" somente sobreposição criaria falsa segurança.
  • Fontes personalizadas (um diretório de fontes do lado do operador) e uma anotação link em annotate_pdf — no roteiro, não na v1.7.0.
  • Verificação ECDSA nativa — pdfnative não exporta ecdsaVerifyHash; verify_pdf mantém seu caminho puro em JS para P-256.
  • Streaming de páginas HTTP — MCP 2026-07-28 ainda não tem structuredContent parcial, então resultados grandes permanecem em disparo único.

Tem uma ideia de recurso? Abra uma issue ou PR.


⭐ Marque o projeto com estrela

Se pdfnative-mcp é útil para você, por favor ⭐ este repositório — e considere também marcar com estrela o motor subjacente Nizoka/pdfnative. Estrelas ajudam outros a descobrir o projeto e motivam o desenvolvimento contínuo.


🤝 Contribuindo

Contribuições são muito bem-vindas. Por favor, leia CONTRIBUTING.md, verifique as issues abertas e siga o código de conduta.


📄 Licença

MIT © 2026 Nizoka. Material de terceiros: THIRD-PARTY-NOTICES.md.

pdfnative-mcp é construído sobre pdfnative e o Model Context Protocol TypeScript SDK.