Cada repositorio acumula datos estructurados que alguien eventualmente necesita como documento: los cambios en una versión, los colaboradores del año, un inventario de API, una lista de riesgos abiertos. Los datos ya están en JSON; el paso que falta es un PDF o archivo Word formateado que un cliente, auditor o gerente abrirá realmente. Con GroupDocs.Assembly.Mcp ejecutándose localmente junto a Claude Code (claude mcp add con dnx GroupDocs.Assembly.Mcp --yes), el agente rellena una plantilla de Word guardada en el repositorio a partir de un archivo JSON del mismo, y escribe el PDF, sin que nadie tenga que formatear una tabla:

Generar el PDF de notas de la versión 4.2.0 a partir de data/release-4.2.0.json con templates/release-notes.docx, y un certificado de contribución para cada colaborador en data/contributors-2026.json.

La versión paso a paso con configuración y solución de problemas está en la documentación: How to generate a PDF or Word report from JSON data in a repository with Claude Code.

¿Por qué no dejar que el agente de codificación escriba el documento?

Los agentes de codificación son muy buenos produciendo datos y bastante malos produciendo documentos. Pídele “notas de la versión como PDF” y generará un archivo Markdown, luego un script que lo convierta, y depurará las fuentes del script. En la siguiente versión lo hará de nuevo, ligeramente diferente. La salida se ve como lo que la biblioteca de conversión tenga por defecto, no como los documentos que tu empresa envía.

Una plantilla fija el aspecto y lo mantiene bajo control de versiones. templates/release-notes.docx es un archivo Word normal con el logotipo, los estilos de encabezado y una tabla, más algunas etiquetas <<…>>. Quien sea responsable del diseño lo edita en Word; el agente nunca lo toca. El JSON lo produce tu herramienta de lanzamiento, o el agente a partir de git log, y esa es la parte que un agente de codificación hace bien.

También hace que el trabajo sea revisable. Un pull request que cambia data/release-4.2.0.json muestra exactamente qué cambios aparecerán en las notas de la versión, línea por línea, en un diff que un revisor puede leer en un minuto. Un pull request que cambia un PDF generado no muestra nada. Mantener los datos y el diseño como archivos separados y versionados, y tratar el documento como algo que se genera a partir de ellos, es la misma idea que separar el código fuente del resultado de la compilación, y se aplica a los documentos por las mismas razones.

Cómo se ve el repositorio

repo/
  data/
    release-4.2.0.json       {"release":{...}, "changes":[...4 items]}
    contributors-2026.json   {"contributors":[...3 items]}
  templates/
    release-notes.docx       <<[release.Version]>>, <<foreach [c in
                             changes]>> table row, counts
    certificate.docx         <<[contributor.Name]>> ...
  out/                       GROUPDOCS_MCP_OUTPUT_PATH, in .gitignore
        |
        |  Claude Code -> GroupDocs.Assembly MCP server (local, stdio)
        v
  release-notes-4.2.0.pdf    pnair.pdf  tvarga.pdf  mrossi.pdf

Las llamadas

Primero el agente verifica qué espera la plantilla, para poder decirte si falta algo en el JSON:

-> get_template_fields {"template":{"filePath":
     "repo/templates/release-notes.docx"}}
<- { "dataSourceNames": [ "release", "changes" ],
     "fields": [ "release.Product", "release.Version", "release.Date",
                 "changes[].Type", "changes[].Title",
                 "changes[].PullRequest", "changes[].Author" ] }

Luego una llamada la renderiza:

-> assemble_document {"template":{"filePath":
     "repo/templates/release-notes.docx"},
     "data":{"filePath":"repo/data/release-4.2.0.json"},
     "format":"pdf","outputName":"release-notes-4.2.0.pdf"}
<- Assembled 'release-notes.docx' with 'release-4.2.0.json' (JSON
   object) as PDF
   Saved to: .../release-notes-4.2.0.pdf

La fila de tabla de la plantilla se repite una vez por cada cambio, y su última línea cuenta los cambios y los autores distintos con changes.Count() y changes.Select(c => c.Author).Distinct().Count(). Esos números provienen de los datos en tiempo de renderizado, no del agente.

Los certificados son una distribución tipo fan‑out: un PDF por cada elemento del arreglo contributors, nombrado según el identificador del colaborador:

-> assemble_per_record {"template":{"filePath":
     "repo/templates/certificate.docx"},
     "data":{"filePath":"repo/data/contributors-2026.json"},
     "recordsPath":"contributors","fileNameField":"Handle",
     "format":"pdf"}
<- Assembled 3 of 3 document(s) from 'certificate.docx' with
   'contributors-2026.json', one per record (each record as
   'contributor'), as PDF.
   Saved to:
   .../pnair.pdf
   .../tvarga.pdf
   .../mrossi.pdf

recordsPath indica al servidor dónde está el arreglo cuando el archivo JSON es un objeto, que es la forma habitual de los archivos de datos reales.

Hazlo un hábito, no un prompt

Los agentes siguen las instrucciones del proyecto sobre cuándo usar una herramienta. Unas cuantas líneas en CLAUDE.md o AGENTS.md convierten esto en una convención:

Documents for people (release notes, reports, certificates) are generated
with the groupdocs-assembly MCP server from templates/*.docx and data/*.json.
Call get_template_fields first; never edit a template. Generated files land
in out/, which is in .gitignore. Dates in JSON as yyyy-MM-ddTHH:mm:ss.

Mantén los resultados fuera de git. Por defecto el servidor escribe junto a su carpeta de almacenamiento; establece GROUPDOCS_MCP_OUTPUT_PATH en el registro del servidor apuntando a la carpeta out/ del repositorio y añádela a .gitignore. El JSON y la plantilla son la fuente; el PDF es un artefacto de compilación, regenerado en segundos, y comprometerlo solo produce diffs que nadie puede revisar.

Límites honestos

  • Modo de evaluación: cada PDF comienza con “Evaluation Only. Created with GroupDocs.Assembly 26.7…”. Está bien para probar; licencia el servidor antes de que cualquier documento salga del equipo.
  • Las plantillas son entrada confiable. Las etiquetas de imagen y documento cargan las rutas y URLs que devuelven sus expresiones, así que trata una plantilla de un pull request como código y proporciona al servidor una única carpeta de almacenamiento.
  • Fechas: escríbelas como 2026-11-03T00:00:00 y formateálas en la plantilla (<<[release.Date]:"d MMMM yyyy">>). Una cadena solo de fecha se desplazó un día en una máquina UTC+2 en nuestra prueba; la imagen Docker se ejecuta en UTC.
  • La generación por registro solo lee JSON, y maxDocuments (por defecto 100) detiene un arreglo inesperadamente grande antes de que se escriba algo.
  • get_template_fields es estático: los valores calculados dentro de proyecciones Select o GroupBy no se siguen.

Preguntas frecuentes

¿Puede Claude Code generar un PDF a partir de JSON en mi repositorio sin un servicio en la nube?
Sí. El servidor MCP se ejecuta localmente como proceso hijo de Claude Code y lee la plantilla y el JSON de la carpeta que le indiques.

¿Puede ejecutarse en CI?
El servidor es un servidor MCP, por lo que necesita un cliente MCP: Claude Code en modo headless, o cualquier ejecutor de agentes. La imagen Docker (ghcr.io/groupdocs-assembly/assembly-net-mcp) es la forma cómoda para una canalización.

¿Word o PDF?
Ambos. Omite format y la salida será un DOCX como la plantilla; "format":"pdf" produce un PDF. get_supported_formats enumera cada objetivo por plantilla.

Profundiza