PDF Letter MCP

Renderiza una carta estructurada como un PDF listo para imprimir con formato DIN 5008, de modo que la dirección quede en la ventana de un sobre alemán, completamente sin conexión y sin API externa.

Documentación

pdf-letter-mcp

Servidor MCP local (stdio) que convierte datos de carta estructurados en un PDF listo para imprimir. Un diseño fijo, la carta alemana cotidiana, con la dirección del destinatario posicionada según DIN 5008 para que quede exactamente en la ventana de los sobres con ventana DL y C6/C5. Sin servicio web, sin API externa, todo funciona sin conexión en tu máquina.

Características

  • Un solo diseño, sin variantes: línea de dirección de remitente, destinatario, "lugar, fecha" alineado a la derecha, bloque de asunto en negrita con referencias debajo, saludo, cuerpo, cierre, firma, anexos
  • Campo de dirección de 45 mm de alto que termina a 105 mm desde la izquierda, con línea de dirección de remitente, zona de observaciones (Einschreiben, Nicht nachsenden) y zona de dirección
  • La dirección de remitente, las observaciones y el destinatario se equilibran dentro del campo de dirección, de modo que el bloque quede uniformemente en la ventana del sobre y las líneas de dirección adicionales aún quepan. addressLayout: "din" vuelve a los límites de zona fijos
  • Los saltos de página mantienen juntos el cierre, la imagen de la firma, el nombre y los anexos; las páginas siguientes llevan destinatario, fecha y número de página
  • Asunto 33 mm debajo del campo de dirección, lugar y fecha tres líneas por encima
  • Marcas de pliegue a 105 mm y 210 mm, marca de perforación a 148,5 mm
  • Margen de escritura DIN 5008 de 25 mm a la izquierda, y el campo de dirección lo sigue, de modo que la dirección, el asunto y el cuerpo comparten un borde. El campo mantiene su borde derecho a 105 mm y queda dentro de la ventana de 90 mm del sobre
  • Cierre, una línea en blanco, nombre impreso. signature.spaceMm reserva más espacio para firmar a mano
  • Firma como archivo de imagen: PNG con canal alfa conserva su transparencia, la imagen se superpone a la línea en blanco sobre el nombre impreso y nunca desplaza el texto. Recorte opcional, eliminación de fondo y recoloración de tinta para escaneos
  • Multilingüe: de, en, fr, es, it, nl, pt, pl, tr, da, sv, cs con formatos de fecha sensibles al idioma y reglas de dirección por país
  • Separación silábica según el idioma, marcado en negrita/cursiva, listas con viñetas y numeradas, saltos de página automáticos con encabezados de continuación
  • Números de página y un modo de depuración de diseño que dibuja las zonas DIN 5008
  • Fuentes Unicode integradas (DejaVu), cualquier fuente del sistema instalada o una ruta .ttf

Instalación

npm install
npm run build

Registra el servidor en Claude Code:

claude mcp add pdf-letter -- node "/absolute/path/to/pdf-letter-mcp/dist/src/index.js"

O en ~/.claude.json / claude_desktop_config.json:

{
  "mcpServers": {
    "pdf-letter": {
      "command": "node",
      "args": ["/absolute/path/to/pdf-letter-mcp/dist/src/index.js"],
      "env": {
        "PDF_LETTER_OUTPUT_DIR": "~/Documents/Briefe"
      }
    }
  }
}

Entorno

VariablePropósito
PDF_LETTER_OUTPUT_DIRDirectorio predeterminado para los PDF generados. Se recurre al directorio temporal del sistema si no se especifica.
PDF_LETTER_FONT_DIRDirectorio adicional que se busca cuando se resuelve una familia de fuentes por nombre.
PDF_LETTER_FONTFamilia de fuentes para cada carta, p. ej. Arial. El valor predeterminado es la DejaVu Sans incluida.
PDF_LETTER_FONT_SIZETamaño de fuente en pt para cada carta, predeterminado 11.
PDF_LETTER_PROFILESRuta a los perfiles de remitente, predeterminado ~/.config/pdf-letter-mcp/profiles.json.
PDF_LETTER_PROFILEPerfil utilizado cuando una carta no menciona ninguno y el archivo no tiene defaultProfile.

Perfiles de remitente

Las direcciones y firmas de los remitentes viven en un archivo de la máquina, nunca en el prompt. Una carta nombra un perfil, el servidor completa la dirección, la línea de dirección de remitente y la imagen de la firma textualmente.

{
  "defaultProfile": "erika",
  "profiles": {
    "erika": {
      "description": "Erika Musterfrau, privat",
      "sender": {
        "name": "Erika Musterfrau",
        "street": "Musterstraße 12",
        "postalCode": "12345",
        "city": "Musterstadt",
        "country": "DE"
      },
      "place": "Musterstadt",
      "locale": "de",
      "signature": { "path": "/pfad/zur/unterschrift.png" }
    }
  }
}

create_letter entonces solo necesita "profile": "erika" más el contenido. El perfil posee la identidad: un remitente o firma pasados en la llamada es reemplazado por el perfil, place, locale y closing son valores predeterminados que una carta puede sobrescribir. list_profiles muestra lo que está disponible. Sin un perfil y sin un remitente, la carta se rechaza en lugar de inventarse.

El archivo pertenece fuera del repositorio, profiles.json está en .gitignore.

El diseño es fijo

Las herramientas MCP solo aceptan contenido: direcciones, fecha, asunto, referencias, texto, firma, anexos. No hay parámetros para márgenes, espaciado, fuente, tamaño o posición de imagen, y los campos desconocidos enviados por un cliente se descartan. La tipografía es una configuración de instalación (PDF_LETTER_FONT, PDF_LETTER_FONT_SIZE), de modo que cada carta de una misma instalación se ve idéntica. Los bloques de construcción para un membrete de empresa, un bloque de información y un pie de página siguen en la biblioteca, pero no son accesibles a través del MCP.

Herramientas

HerramientaPropósito
create_letterRenderiza la carta y escribe el PDF. Devuelve ruta, recuento de páginas, métricas de diseño y advertencias.
preview_letterMismo renderizado sin escribir un archivo, para revisar el diseño.
prepare_signatureLimpia una firma escaneada (recorte, fondo transparente, color de tinta) y escribe un PNG.
get_din5008_specDevuelve la geometría en milímetros de un formulario.
list_localesLista los idiomas admitidos y sus textos fijos.
list_fontsLista familias integradas y resuelve un nombre de fuente contra las fuentes del sistema instaladas.

create_letter

El remitente aparece solo en la pequeña línea de dirección de remitente sobre el destinatario. Lugar y fecha se sitúan alineados a la derecha sobre el bloque de asunto en negrita, las referencias van directamente debajo del asunto.

{
  "locale": "de",
  "sender": {
    "name": "Erika Musterfrau",
    "street": "Musterstraße 12",
    "postalCode": "12345",
    "city": "Musterstadt",
    "country": "DE"
  },
  "recipient": {
    "company": "Stadtwerke Musterstadt",
    "street": "Industriestraße 8",
    "postalCode": "12345",
    "city": "Musterstadt"
  },
  "place": "Musterstadt",
  "date": "2026-07-24",
  "dateStyle": "long",
  "subject": "Widerspruch gegen die Jahresabrechnung vom 01.07.2026",
  "subjectLines": ["Zeichen: SW-2026-0815", "Kunden-Nummer: 000000000"],
  "body": "hiermit widerspreche ich der Jahresabrechnung.\n\n- korrigierte Abrechnung\n- Eingangsbestätigung",
  "signature": {
    "path": "/pfad/zur/unterschrift.png",
    "widthMm": 45,
    "removeBackground": true,
    "trim": true,
    "name": "Erika Musterfrau"
  },
  "enclosures": ["Kopie der Abrechnung"]
}

Todo excepto sender, recipient y body es opcional. El saludo se deriva del destinatario (Frau más Dr. Erika Mustermann se convierte en Sehr geehrte Frau Dr. Mustermann,), la fecha se establece por defecto al hoy, el cierre al valor predeterminado del idioma.

Marcado del cuerpo

  • Línea en blanco: nuevo párrafo
  • Salto de línea simple: salto de línea (establece bodyMode a markdown para reorganizar el flujo en su lugar)
  • - item o 1. item: lista con viñetas o numerada
  • **bold**, *italic*
  • \pagebreak en su propia línea: salto de página forzado

Firma

Dos formas, ambas terminan como una imagen real en el PDF:

  1. Pasa el archivo directamente: signature.path más trim y removeBackground. El escaneo se limpia en cada renderizado.
  2. Límpialo una vez con prepare_signature y reutiliza el PNG resultante. Más rápido y te permite revisar el resultado antes de que entre en una carta.

trim, removeBackground y inkColor necesitan la dependencia opcional sharp, que se instala por defecto. Un PNG que ya tenga fondo transparente funciona sin ella.

La imagen es una superposición: cierre, una línea en blanco, nombre impreso permanecen exactamente donde están, y la firma se coloca sobre esa línea en blanco y sobre el cierre, como se escribe una firma sobre "Mit freundlichen Grüßen" en papel. Ese solapamiento es el resultado previsto.

El tamaño y la posición los decide el renderizador, no el llamante. La firma se escala aproximadamente al ancho de la línea de cierre, alrededor de 50 mm, con un límite proporcional de 1,2 veces ese ancho y 28 mm de alto. No hay parámetro para ancho, alto, desplazamiento o espaciado, por lo que nada puede cambiar el diseño carta por carta.

Verificación

npm test          # geometry, address rules, typography, rendering
npm run examples  # writes sample letters to examples/

examples/ contiene la carta alemana, la misma carta en inglés y una variante de depuración que dibuja las zonas DIN 5008, de modo que se puede comprobar la posición del campo de dirección contra un sobre con ventana. preview_letter informa las mismas medidas como JSON, además de advertencias cuando la dirección es demasiado larga o no cabe en el campo de dirección.

Licencia

MIT, ver LICENSE. Las fuentes DejaVu incluidas están cubiertas por las licencias Bitstream Vera y Arev.