Pdfops MCP

Operaciones rápidas en archivos PDF

Documentación

pdfops

Herramientas PDF rápidas para agentes de IA.
Un solo binario, 31 herramientas, JSON de entrada y salida. Funciona como CLI, servidor MCP y biblioteca de Rust.

CI crates.io npm release MIT license

$ pdfops tables invoice.pdf --format markdown        # tables as tables, not as a blob of text
$ pdfops redact contract.pdf --text "Jan Kowalski" -o safe.pdf   # removed from the file, then verified
$ pdfops text scan.pdf --ocr --ocr-lang pol+eng      # OCR only where there is no text layer
$ pdfops stamp offer.pdf --image signature.png --x 380 --y 690 -o signed.pdf

Por qué pdfops

  • Diseñado para agentes. Cada comando devuelve un documento JSON, los errores indican qué hacer a continuación y el texto se puede leer bajo un presupuesto de caracteres con un punto de reanudación.
  • Todo en un solo lugar. Lectura, diseño, tablas, OCR, renderizado, cirugía de páginas, sellado, redacción, anotaciones, firmas, formularios, cifrado, inspección y creación: 31 herramientas detrás de un solo esquema.
  • Sin configuración. Un único binario sin bibliotecas PDF, sin Python y sin tiempo de ejecución. Solo el OCR necesita un programa adicional, y pdfops puede obtener los datos de idioma por sí mismo.
  • Rápido. Los archivos se abren en milisegundos sin importar su tamaño, y el trabajo de páginas se ejecuta en todos los núcleos. Consulta los puntos de referencia.
  • Redacción confiable. El contenido se elimina de la página, no se cubre, y el resultado se verifica con un segundo intérprete antes de escribir cualquier cosa.
  • Seguro en archivos que no escribiste. Cada comando se ejecuta bajo un límite de memoria y un límite de tiempo, el servidor MCP ejecuta cada llamada en un proceso propio y se puede confinar a un directorio, y cada comando se prueba contra un corpus de 988 PDF hostiles y malformados en CI.
  • Sabe qué está haciendo un archivo. scan informa scripts, acciones que se activan solas, programas adjuntos, nombres disfrazados y texto que se extrae pero no se puede ver, el portador de la inyección de prompts. sanitize elimina el contenido activo y lo demuestra escaneando el resultado.

Inicio rápido

Como servidor MCP, sin nada instalado previamente:

{
  "mcpServers": {
    "pdfops": { "command": "npx", "args": ["-y", "pdfops-cli", "mcp"] }
  }
}

Para Claude Code: claude mcp add pdfops -- npx -y pdfops-cli mcp.

Las herramientas se llaman pdf_info, pdf_text, pdf_redact y así sucesivamente, y aceptan los mismos argumentos que la CLI. Las rutas relativas se resuelven contra el directorio de trabajo del servidor.

Para mantener a un agente dentro de una carpeta, agrega --root: se rechaza toda ruta fuera de ella, incluidas las rutas que llegan dentro de un documento, y las rutas relativas se resuelven contra ella.

{ "command": "npx", "args": ["-y", "pdfops-cli", "mcp", "--root", "/home/me/documents"] }

Instalación

MétodoComandoRequiere
npmnpm install -g pdfops-cli o npx pdfops-cliNode 18+
Precompilado, vía cargocargo binstall pdfopscargo-binstall
Desde el código fuentecargo install pdfopsRust 1.92+
Dockerdocker run --rm -i -v "$PWD:/work" ghcr.io/kayzedd/pdfops mcp --root /workDocker
Manualdescarga un archivo y pon pdfops en tu PATHnada

El paquete npm se llama pdfops-cli e instala el comando pdfops. Es un pequeño lanzador: en la primera ejecución descarga el binario para tu plataforma desde la versión de GitHub, lo verifica contra la suma SHA-256 publicada y lo almacena en caché. Los binarios precompilados cubren Linux (glibc y musl) y macOS en x86-64 y ARM64, y Windows en x86-64. La imagen de Docker es Alpine con pdfops y tesseract con inglés; agrega -v para la carpeta en la que trabajar.

El OCR además necesita el programa tesseract; nada más lo necesita. Los datos de idioma se descargan a petición, sin derechos de administrador:

pdfops ocr-langs                     # is tesseract there, which languages can be used
pdfops ocr-install --lang pol+eng    # download language data into the user's data directory
pdfops ocr-install --engine          # install tesseract itself where that needs no password

Herramientas

ComandoQué hace
LeerinfoNúmero de páginas, tamaño de página, metadatos, cifrado, esquema y resumen de formularios
textTexto página por página, con un presupuesto de caracteres y respaldo OCR opcional
searchBusca texto o una expresión regular, devuelve páginas y fragmentos
layoutCuadro delimitador, fuente y tamaño de cada línea o palabra
tablesTablas como filas de celdas, Markdown o CSV
outlineMarcadores con páginas de destino
annotationsResaltados, comentarios, enlaces y otro marcado, con posiciones
signaturesFirmas digitales: quién firmó y si el documento cambió desde entonces
renderPáginas a PNG, para ver gráficos, escaneos y diseño
imagesLas imágenes dibujadas en las páginas, como archivos
ocrTexto reconocido de páginas escaneadas, opcionalmente escrito en una copia buscable
scanScripts, acciones automáticas, adjuntos, contenido disfrazado y texto oculto, por gravedad
ConstruircreateUn nuevo PDF desde Markdown
mergeVarios PDF en uno
pagesConservar, reordenar, duplicar o eliminar páginas
splitDividir por número de páginas o por rangos
EditarrotateRotar páginas en múltiplos de 90 grados
stampMarca de agua, encabezado, pie de página, números de página, una imagen como una firma o un código QR
annotateAgregar un resaltado, subrayado, tachado, cuadro, nota o enlace
replaceReemplazar texto en su lugar, en la fuente propia del documento cuando sea posible
redactEliminar texto, imágenes y dibujos en áreas o texto coincidente, luego verificar
set-metaTítulo, autor, asunto, palabras clave, creador
compressReducir: sin pérdida por defecto, opcionalmente recodificando y reduciendo la escala de las imágenes
FormulariosformsCampos con sus tipos, valores y opciones
fillRellenar campos por nombre
ProtegerencryptContraseñas y permisos AES-256
decryptEliminar la protección con contraseña
signFirmar digitalmente con un certificado, manteniendo válidas las firmas anteriores
sanitizeEliminar scripts, acciones riesgosas, adjuntos, XFA y medios, luego verificar escaneando
Configuraciónocr-langsSi tesseract está instalado y qué idiomas son utilizables
ocr-installDescargar datos de idioma OCR, opcionalmente instalar tesseract

Ejecuta pdfops <command> --help para las opciones de cada uno.

Ejemplos

$ pdfops info manual.pdf
{"encrypted":false,"file":"manual.pdf","form_fields":0,
 "metadata":{"created":"2026-06-30T09:07:46+00:00","producer":"GPL Ghostscript 10.07.1"},
 "outline_entries":645,"page_size_pt":{"height":792.0,"width":595.0},"pages":357,"pdf_version":"1.3",
 "size_bytes":1386723,"uniform_page_size":true}

$ pdfops search manual.pdf "calling convention" --max-results 1 --context 40
{"file":"manual.pdf","matches":[{"match":"Calling Convention","page":12,
 "snippet":"... 10.5.1 The Pascal Calling Convention ..."}],"query":"calling convention",
 "total_matches":17,"unreadable_pages":[]}

Lectura:

pdfops text manual.pdf --pages 12- --max-chars 4000     # resume_at_page says where to continue
pdfops text scan.pdf --ocr --ocr-lang pol+eng           # OCR only the pages that have no text
pdfops tables report.pdf --pages 4 --format markdown
pdfops layout report.pdf --pages 4 --level words        # bbox, font and size per word
pdfops render report.pdf --pages 1-3 --dpi 150 -o out/  # look at charts and layout
pdfops --stream ocr scan.pdf --lang pol                 # a line per page as it finishes
pdfops ocr scan.pdf --lang pol -o searchable.pdf        # the same file, with text to search
pdfops images report.pdf -o images/

Construcción y trabajo de páginas:

pdfops create notes.md -o notes.pdf
pdfops merge a.pdf b.pdf -o merged.pdf
pdfops pages in.pdf --keep "3,1,5-" -o out.pdf
pdfops split in.pdf --every 10 -o parts/

Edición:

pdfops stamp in.pdf --text "Poufne · {page}/{pages}" --position footer -o out.pdf
pdfops stamp in.pdf --image signature.png --x 380 --y 690 --width 140 --pages last -o out.pdf
pdfops stamp in.pdf --qr "https://example.com/doc/42" --anchor bottom-right -o out.pdf
pdfops redact in.pdf --text "Jan Kowalski" --text "\d{11}" --regex -o redacted.pdf
pdfops redact in.pdf --rect "2:100,200,300,220" -o redacted.pdf
pdfops replace in.pdf --find "2025" --with "2026" -o out.pdf
pdfops replace in.pdf --find "2025" --with "2026" --dry-run -o out.pdf   # the plan, nothing written
pdfops compress in.pdf --max-image-edge 1600 --image-quality 70 -o small.pdf

Formularios y protección:

pdfops forms form.pdf
pdfops fill form.pdf --set name="Ada Lovelace" --set agree=true -o filled.pdf
pdfops encrypt in.pdf --owner-password secret --deny-copy -o locked.pdf
pdfops sign in.pdf --p12 identity.p12 --p12-password secret --reason "Approved" -o signed.pdf
pdfops sign in.pdf --cert me.crt --key me.key --visible "1:360,700,560,760" -o signed.pdf
pdfops signatures signed.pdf                            # valid, unchanged, who and when
pdfops signatures signed.pdf --trust company-root.pem   # and whether the signer is one of yours
pdfops sign in.pdf --p12 identity.p12 --tsa http://timestamp.digicert.com -o signed.pdf
pdfops scan inbox/offer.pdf                             # what is in it, before reading it
pdfops sanitize inbox/offer.pdf -o offer-clean.pdf      # scripts, actions, attachments removed

Marcado:

pdfops annotate in.pdf --text "liability" --comment "check with legal" -o marked.pdf
pdfops annotate in.pdf --kind link --rect "1:72,50,300,70" --url https://example.com -o out.pdf
pdfops annotations marked.pdf

Convenciones

  • Salida. Cada comando imprime un documento JSON en stdout. Los errores van a stderr como {"error": "..."} con estado de salida 1. Agrega --pretty para sangrar.
  • Progreso. Con --stream, ocr, text --ocr, render, images, split, redact y replace se imprime una línea de JSON por página o archivo terminado, {"event":"progress","step":"render","done":7,"total":20,"page":12,...}, y el resultado habitual como la última línea. Las páginas se procesan en paralelo, por lo que los eventos llegan en el orden en que el trabajo termina; cada uno nombra su página y done aumenta en uno por línea. A través de MCP, los mismos eventos llegan como notifications/progress cuando la llamada lleva un token de progreso.
  • Escritura. Los comandos que escriben aceptan -o. Puede ser el archivo de entrada: la salida pasa por un archivo temporal.
  • Páginas están basadas en 1 y separadas por comas: 3, 2-5, 7- (hasta el final), -4 (desde el inicio), 5-2 (descendente), last, odd, even, all.
  • Posiciones están en puntos con el origen en la esquina superior izquierda de la página tal como se muestra, y creciendo hacia abajo. layout las informa, stamp --x/--y y redact --rect las aceptan, y un píxel de render --dpi 72 es exactamente un punto.

Cómo se compara

pdfopsPyMuPDFpypdfpdfplumberqpdfpoppler-utils
Extracción de texto✓✓✓✓–✓
Posiciones de palabras y fuentes✓✓–✓–posiciones
Tablas✓✓–✓––
Renderizar páginas✓✓–✓–✓
OCR✓✓––––
Fusionar, dividir, reordenar, rotar✓✓✓–✓parcialmente
Sellos de texto, imagen y QR✓✓por superposición–por superposición–
Redacción que elimina contenido✓✓––––
Redacción verificada antes de escribir✓–––––
Reemplazar texto en su lugar✓–––––
Rellenar formularios✓✓✓–––
Cifrar y descifrar✓✓✓–✓–
Agregar y listar anotaciones✓✓✓listar––
Firmar digitalmente✓–––––
Verificar firmas✓––––✓
Inspeccionar contenido activo y texto oculto✓–––––
Eliminar contenido activo✓✓––––
Límites de memoria y tiempo por llamada✓–––––
Crear desde Markdown✓desde HTML––––
Servidor MCP integrado y esquemas de herramientas✓–––––
JSON desde cada comando✓bibliotecabibliotecabibliotecaparcialmente–
Tiempo de ejecución necesarioningunoPythonPythonPythonningunoninguno
LicenciaMITAGPL o comercialBSDMITApache-2.0GPL

PyMuPDF es el más cercano en alcance y es una biblioteca excelente; está escrito en C, necesita Python, y su licencia AGPL importa si lo distribuyes. pdfops intercambia algo de amplitud por un único binario con licencia MIT cuyas herramientas un agente puede llamar directamente.

Puntos de referencia

Mejor de 3 ejecuciones de proceso completo, incluido el inicio, ya que eso es lo que cuesta una llamada de herramienta a un agente. Documento: el manual de NASM 2.16, 308 páginas y 1.2 MB; images en un libro de 352 páginas y 2.6 MB con imágenes; formularios en un formulario de una página. Máquina: AMD Ryzen 7 9800X3D de 8 núcleos, Windows 11. Versiones: poppler 25.07, qpdf 12.4, PyMuPDF 1.28, pypdf 6.19, pdfplumber 0.11, pyHanko 0.37 (CLI 0.5), tesseract 5.5. La entrada más rápida de cada fila está en negrita; n/a marca una herramienta que estaba instalada y no completó la tarea. La entrada de PyMuPDF para sanitize es su scrub.

Tareapdfopsherramienta de línea de comandosPyMuPDFpypdfpdfplumber
info7 mspdfinfo 12 ms129 ms203 ms222 ms
text, todas las páginas53 mspdftotext 540 ms297 ms1273 ms11.3 s
search, todas las páginas53 ms-326 ms--
layout, cada palabra con su cuadro194 ms-346 ms-10.9 s
tables, 50 páginas20 ms-1558 ms-1629 ms
outline15 ms-128 ms221 ms-
render, 20 páginas a 150 dpi41 mspdftoppm 2677 ms593 ms--
ocr, una página1087 mstesseract 759 ms---
images, todas las imágenes incrustadas230 mspdfimages 5621 ms1297 ms1553 ms-
create, 100 secciones de Markdown12 ms----
merge, tres copias57 msqpdf 204 ms401 ms2037 ms-
pages, conservar 1017 msqpdf 138 ms138 ms285 ms-
split, un archivo por página156 mspdfseparate 46.0 s437 ms2513 ms-
rotate, todas las páginas20 msqpdf 144 ms147 ms769 ms-
stamp, texto en cada página21 ms-279 ms--
stamp, código QR en cada página121 ms----
annotations, lista18 ms-227 ms-309 ms
annotate, resaltar una palabra en cada página291 ms-700 ms--
redact, una palabra en cada página564 ms-1926 ms--
replace, una palabra en cada página575 ms----
scan, estructura y texto oculto232 ms----
scan, solo estructura16 ms----
sanitize32 ms-2072 ms--
set-meta19 ms-140 ms771 ms-
compress31 msqpdf 179 ms378 ms--
encrypt, AES-25625 msqpdf 174 ms150 ms825 ms-
decrypt38 msqpdf 170 ms158 ms875 ms-
sign, RSA-204823 mspyhanko 615 ms---
signatures, verificar16 mspdfsig n/a---
forms, listar campos7 ms-121 ms169 ms-
fill, un campo9 ms-130 ms198 ms-

Reproducir con scripts/bench.py en cualquier documento.

Por qué es rápido: info, layout, tables, render, images y ocr leen objetos bajo demanda, por lo que abrir un archivo cuesta unos pocos milisegundos sea cual sea su tamaño. La extracción de texto, el diseño, las tablas, el renderizado, la división, la exportación de imágenes y el OCR se ejecutan en todos los núcleos. Las operaciones de página copian solo los objetos a los que llegan las páginas seleccionadas, por lo que el tamaño de salida y el tiempo siguen a la selección, no al origen.

Uso sin MCP

pdfops tools imprime [{"name", "description", "inputSchema"}] para cada comando. Pásalos a cualquier función que llame a la API y luego ejecuta la llamada a través de la CLI o la biblioteca.

let result = pdfops::tools::call(
    "pdf_text",
    serde_json::json!({"input": "report.pdf", "pages": "1-3"}),
)?;

Los puntos de entrada tipados viven en pdfops::ops, por ejemplo pdfops::ops::read::text(TextArgs { .. }).

Comportamiento que vale la pena conocer

La versión corta. pdfops <command> --help tiene el detalle de cada comando.

  • Cualquier script. El texto que stamp, fill, replace, create y ocr -o dibujan se moldea y se incrusta como subconjuntos de fuentes; donde ninguna fuente tiene todos los caracteres, varias comparten el texto. El hebreo y el árabe se componen de derecha a izquierda y se leen de vuelta en el orden en que se leen, por lo que una palabra se encuentra escribiéndola. Algunos grupos índicos y tailandeses que el propio pdfops escribió se leen de vuelta con sus caracteres reagrupados.
  • La redacción elimina, no cubre. Los glifos, los píxeles de imagen en cualquier codificación, los dibujos y las anotaciones bajo un área se eliminan, un texto a redactar también se elimina de los metadatos y marcadores, y el resultado es leído de vuelta por un segundo intérprete antes de escribir nada.
  • Reemplazar escribe en la fuente propia del documento donde tiene los glifos y mueve el resto de la línea; los valores de los campos de texto y los comentarios de las anotaciones también se cambian. Una línea que crece más allá de su columna pasa sus últimas palabras a la siguiente línea, y el párrafo recibe una línea más si hay espacio debajo. Donde el párrafo no se puede determinar con certeza, la línea se deja como está y overflow_pt dice en cuánto se excede; --dry-run lo muestra primero.
  • Ejecución de prueba. redact, replace, annotate y stamp aceptan --dry-run: todo el trabajo, nada escrito.
  • Escaneo informa scripts, acciones, adjuntos, contenido disfrazado y texto oculto por severidad. No es un escáner de virus y nunca llama seguro a un archivo. Sanear elimina el contenido activo y escanea el resultado antes de escribirlo.
  • Tablas con líneas de regla se leen celda por celda. Las tablas sin ellas se infieren por la alineación (detected_by: alignment) y merecen una revisión.
  • OCR es el de tesseract. ocr -o escribe el texto reconocido en una copia como una capa invisible.
  • Firmas. sign añade, por lo que las firmas anteriores siguen siendo válidas. Puede mostrar la firma en una página (--visible) e incrustar la declaración de tiempo de una autoridad de sellado de tiempo (--tsa). signatures comprueba que los bytes no han cambiado y quién firmó; con --trust comprueba la cadena del firmante contra certificados que tú nombras, y con --revocation sus listas de revocación. Cualquier otro cambio en un PDF firmado invalida sus firmas, como debe ser.
  • Fusión y trabajo de páginas conservan marcadores y enlaces que llevan a páginas en la salida, y renombran los campos de formulario de entradas posteriores doc2.<name> para que nombres iguales no compartan un valor.
  • Archivos dañados se reparan para lectura y se reconstruyen para escritura; el resultado lleva entonces repaired_inputs. Un archivo dañado que también está cifrado no se reconstruye. Los archivos protegidos siguen protegidos al editarse; solo decrypt elimina la protección.
  • Límites. 4 GiB y 300 segundos por comando por defecto: --max-memory, --timeout, o PDFOPS_MAX_MEMORY y PDFOPS_TIMEOUT; 0 levanta un límite. Los rásteres están limitados a 64 megapíxeles.
  • Crear acepta Markdown, y el HTML en él por lo que dice: encabezados, énfasis, enlaces, listas, tablas. Cómo debería verse no se lee: no hay CSS.

Desarrollo

cargo test                                # under a second; fixtures are generated in memory
cargo test -- --ignored                   # OCR test, needs tesseract with a language pack
cargo clippy --all-targets -- -D warnings
cargo fmt --check
scripts/bench.py --help                   # regenerate the benchmark table

Construido sobre lopdf (modelo de objetos), hayro (texto, renderizado, posiciones y decodificación de imágenes), rustybuzz (moldeado de texto), subsetter (incrustación de fuentes) y pulldown-cmark (Markdown).

Licencia

MIT