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.spaceMmreserva 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
| Variable | Propósito |
|---|---|
PDF_LETTER_OUTPUT_DIR | Directorio predeterminado para los PDF generados. Se recurre al directorio temporal del sistema si no se especifica. |
PDF_LETTER_FONT_DIR | Directorio adicional que se busca cuando se resuelve una familia de fuentes por nombre. |
PDF_LETTER_FONT | Familia de fuentes para cada carta, p. ej. Arial. El valor predeterminado es la DejaVu Sans incluida. |
PDF_LETTER_FONT_SIZE | Tamaño de fuente en pt para cada carta, predeterminado 11. |
PDF_LETTER_PROFILES | Ruta a los perfiles de remitente, predeterminado ~/.config/pdf-letter-mcp/profiles.json. |
PDF_LETTER_PROFILE | Perfil 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
| Herramienta | Propósito |
|---|---|
create_letter | Renderiza la carta y escribe el PDF. Devuelve ruta, recuento de páginas, métricas de diseño y advertencias. |
preview_letter | Mismo renderizado sin escribir un archivo, para revisar el diseño. |
prepare_signature | Limpia una firma escaneada (recorte, fondo transparente, color de tinta) y escribe un PNG. |
get_din5008_spec | Devuelve la geometría en milímetros de un formulario. |
list_locales | Lista los idiomas admitidos y sus textos fijos. |
list_fonts | Lista 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
bodyModeamarkdownpara reorganizar el flujo en su lugar) - itemo1. item: lista con viñetas o numerada**bold**,*italic*\pagebreaken su propia línea: salto de página forzado
Firma
Dos formas, ambas terminan como una imagen real en el PDF:
- Pasa el archivo directamente:
signature.pathmástrimyremoveBackground. El escaneo se limpia en cada renderizado. - Límpialo una vez con
prepare_signaturey 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.