PDF Letter MCP
Renderiza uma carta estruturada como um PDF pronto para impressão, formatado conforme a DIN 5008, de modo que o endereço fique na janela de um envelope alemão, totalmente offline, sem API externa.
Documentação
pdf-letter-mcp
Servidor MCP local (stdio) que transforma dados de carta estruturados em um PDF pronto para impressão. Um layout fixo, a carta alemã do dia a dia, com o endereço do destinatário posicionado conforme a DIN 5008, de modo que fique exatamente na janela de envelopes com janela DL e C6/C5. Sem serviço web, sem API externa, tudo roda offline na sua máquina.
Recursos
- Um layout, sem variantes: linha de endereço de remetente, destinatário, "local, data" alinhado à direita, bloco de assunto em negrito com referências abaixo, saudação, corpo, fechamento, assinatura, anexos
- Campo de endereço com 45 mm de altura, terminando a 105 mm da esquerda, com linha de endereço de remetente, zona de observação (Einschreiben, Nicht nachsenden) e zona de endereço
- Endereço de remetente, observações e destinatário são equilibrados dentro do campo de endereço, de modo que o bloco fique uniforme na janela do envelope e linhas adicionais de endereço ainda caibam.
addressLayout: "din"volta aos limites fixos da zona - Quebras de página mantêm fechamento, imagem de assinatura, nome e anexos juntos; páginas subsequentes trazem destinatário, data e número da página
- Assunto 33 mm abaixo do campo de endereço, local e data três linhas acima
- Marcas de dobra em 105 mm e 210 mm, marca de perfuração em 148,5 mm
- Margem de escrita DIN 5008 de 25 mm à esquerda, e o campo de endereço a segue, de modo que endereço, assunto e corpo compartilham uma borda. O campo mantém a borda direita em 105 mm e permanece dentro da janela de 90 mm do envelope
- Fechamento, uma linha em branco, nome impresso.
signature.spaceMmreserva mais espaço para assinatura à mão - Assinatura como arquivo de imagem: PNG com canal alfa mantém a transparência; a imagem é sobreposta à linha em branco acima do nome impresso e nunca desloca o texto. Recorte opcional, remoção de fundo e recolorir da tinta para digitalizações
- Multilíngue: de, en, fr, es, it, nl, pt, pl, tr, da, sv, cs, com formatos de data sensíveis ao idioma e regras de endereço por país
- Hifenização sensível ao idioma, marcação em negrito/itálico, listas com marcadores e numeradas, quebras de página automáticas com cabeçalhos de continuação
- Números de página e um modo de depuração de layout que desenha as zonas DIN 5008
- Fontes Unicode incorporadas (DejaVu), qualquer fonte do sistema instalada ou um caminho .ttf
Instalação
npm install
npm run build
Registre o servidor no Claude Code:
claude mcp add pdf-letter -- node "/absolute/path/to/pdf-letter-mcp/dist/src/index.js"
Ou no ~/.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"
}
}
}
}
Ambiente
| Variável | Finalidade |
|---|---|
PDF_LETTER_OUTPUT_DIR | Diretório padrão para os PDFs gerados. Recorre ao diretório temporário do sistema. |
PDF_LETTER_FONT_DIR | Diretório adicional que é pesquisado quando uma família de fontes é resolvida por nome. |
PDF_LETTER_FONT | Família de fontes para cada carta, ex.: Arial. O padrão é a DejaVu Sans incorporada. |
PDF_LETTER_FONT_SIZE | Tamanho da fonte em pt para cada carta, padrão 11. |
PDF_LETTER_PROFILES | Caminho para os perfis de remetente, padrão ~/.config/pdf-letter-mcp/profiles.json. |
PDF_LETTER_PROFILE | Perfil usado quando uma carta não indica nenhum e o arquivo não possui defaultProfile. |
Perfis de remetente
Endereços de remetentes e assinaturas ficam em um arquivo na máquina, nunca no prompt. Uma carta nomeia um perfil; o servidor preenche endereço, linha de endereço de remetente e imagem de assinatura literalmente.
{
"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 então precisa apenas de "profile": "erika" mais o conteúdo. O perfil é o dono da identidade: um remetente ou assinatura passado na chamada é substituído pelo perfil; place, locale e closing são padrões que uma carta pode sobrescrever. list_profiles mostra o que está disponível. Sem perfil e sem remetente, a carta é recusada em vez de ser inventada.
O arquivo fica fora do repositório; profiles.json está em .gitignore.
O layout é fixo
As ferramentas MCP aceitam apenas conteúdo: endereços, data, assunto, referências, texto, assinatura, anexos. Não há parâmetros para margens, espaçamento, fonte, tamanho ou posição de imagem, e campos desconhecidos enviados por um cliente são descartados. A tipografia é uma configuração de instalação (PDF_LETTER_FONT, PDF_LETTER_FONT_SIZE), de modo que toda carta de uma instalação parece idêntica. Os blocos de construção para um cabeçalho de empresa, um bloco de informações e um rodapé ainda estão na biblioteca, mas não são acessíveis por meio do MCP.
Ferramentas
| Ferramenta | Finalidade |
|---|---|
create_letter | Renderiza a carta e grava o PDF. Retorna caminho, número de páginas, métricas de layout e avisos. |
preview_letter | Mesma renderização sem gravar arquivo, para verificar o layout. |
prepare_signature | Limpa uma assinatura digitalizada (recorte, fundo transparente, cor da tinta) e grava um PNG. |
get_din5008_spec | Retorna a geometria em milímetros de um formulário. |
list_locales | Lista os idiomas suportados e seus textos fixos. |
list_fonts | Lista as famílias incorporadas e resolve um nome de fonte contra as fontes do sistema instaladas. |
create_letter
O remetente aparece apenas na pequena linha de endereço de remetente acima do destinatário. Local e data ficam alinhados à direita acima do bloco de assunto em negrito; as referências vão diretamente abaixo do assunto.
{
"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"]
}
Tudo, exceto sender, recipient e body, é opcional. A saudação é derivada do destinatário (Frau mais Dr. Erika Mustermann vira Sehr geehrte Frau Dr. Mustermann,), a data tem como padrão hoje, e o fechamento, o padrão do idioma.
Marcação do corpo
- Linha em branco: novo parágrafo
- Nova linha simples: quebra de linha (defina
bodyModecomomarkdownpara refluir) - itemou1. item: lista com marcadores ou numerada**bold**,*italic*\pagebreakem linha própria: quebra de página forçada
Assinatura
Duas formas, ambas resultam em uma imagem real no PDF:
- Passe o arquivo diretamente:
signature.pathmaistrimeremoveBackground. A digitalização é limpa a cada renderização. - Limpe uma vez com
prepare_signaturee reutilize o PNG resultante. Mais rápido e permite verificar o resultado antes de ir para a carta.
trim, removeBackground e inkColor precisam da dependência opcional sharp, que é instalada por padrão. Um PNG que já tem fundo transparente funciona sem ela.
A imagem é uma sobreposição: fechamento, uma linha em branco e nome impresso permanecem exatamente onde estão, e a assinatura fica por cima dessa linha em branco e atravessando o fechamento, do mesmo modo que uma assinatura é escrita sobre "Mit freundlichen Grüßen" no papel. Essa sobreposição é o resultado pretendido.
Tamanho e posição são decididos pelo renderizador, não pelo chamador. A assinatura é dimensionada para aproximadamente a largura da linha de fechamento, cerca de 50 mm, limitada proporcionalmente a 1,2 vezes essa largura e 28 mm de altura. Não há parâmetro para largura, altura, deslocamento ou espaçamento, então nada pode deslocar o layout carta a carta.
Verificação
npm test # geometry, address rules, typography, rendering
npm run examples # writes sample letters to examples/
examples/ contém a carta alemã, a mesma carta em inglês e uma variante de depuração que desenha as zonas DIN 5008, para que a posição do campo de endereço possa ser verificada contra um envelope com janela. preview_letter relata as mesmas medidas como JSON, além de avisos quando o endereço é muito longo ou não cabe no campo de endereço.
Licença
MIT, veja LICENSE. As fontes DejaVu incorporadas são cobertas pelas licenças Bitstream Vera e Arev.