Skip to main content
Glama
bitterdev

pdf-letter-mcp

by bitterdev

pdf-letter-mcp

Local MCP server (stdio) that turns structured letter data into a print ready PDF. One fixed layout, the everyday German letter, with the recipient address positioned per DIN 5008 so it sits exactly in the window of DL and C6/C5 window envelopes. No web service, no external API, everything runs offline on your machine.

Features

  • One layout, no variants: return address line, recipient, right aligned "place, date", bold subject block with references below it, salutation, body, closing, signature, enclosures

  • Address field 45 mm high ending at 105 mm from the left, with return address line, remark zone (Einschreiben, Nicht nachsenden) and address zone

  • Return address, remarks and recipient are balanced inside the address field, so the block sits evenly in the envelope window and further address lines still fit. addressLayout: "din" switches back to the fixed zone boundaries

  • Page breaks keep closing, signature image, name and enclosures together, follow-up pages carry recipient, date and page number

  • Subject 33 mm below the address field, place and date three lines above it

  • Fold marks at 105 mm and 210 mm, punch mark at 148.5 mm

  • DIN 5008 writing margin of 25 mm on the left, and the address field follows it, so address, subject and body share one edge. The field keeps its right edge at 105 mm and stays inside the 90 mm envelope window

  • Closing, one blank line, printed name. signature.spaceMm reserves more room for signing by hand

  • Signature as an image file: PNG with alpha channel keeps its transparency, the image is laid over the blank line above the printed name and never shifts the text. Optional crop, background removal and ink recolouring for scans

  • Multilingual: de, en, fr, es, it, nl, pt, pl, tr, da, sv, cs with locale aware date formats and address rules per country

  • Language aware hyphenation, bold/italic markup, bullet and numbered lists, automatic page breaks with continuation headers

  • Page numbers and a layout debug mode that draws the DIN 5008 zones

  • Embedded Unicode fonts (DejaVu), any installed system font or a .ttf path

Related MCP server: einvoice-mcp

Install

npm install
npm run build

Register the server in Claude Code:

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

Or in ~/.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"
      }
    }
  }
}

Environment

Variable

Purpose

PDF_LETTER_OUTPUT_DIR

Default directory for generated PDFs. Falls back to the system temp directory.

PDF_LETTER_FONT_DIR

Additional directory that is searched when a font family is resolved by name.

PDF_LETTER_FONT

Font family for every letter, e.g. Arial. Default is the bundled DejaVu Sans.

PDF_LETTER_FONT_SIZE

Font size in pt for every letter, default 11.

PDF_LETTER_PROFILES

Path to the sender profiles, default ~/.config/pdf-letter-mcp/profiles.json.

PDF_LETTER_PROFILE

Profile used when a letter names none and the file has no defaultProfile.

Sender profiles

Sender addresses and signatures live in a file on the machine, never in the prompt. A letter names a profile, the server fills in address, return address line and signature image verbatim.

{
  "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 then only needs "profile": "erika" plus the content. The profile owns the identity: a sender or signature passed in the call is replaced by the profile, place, locale and closing are defaults that a letter may override. list_profiles shows what is available. Without a profile and without a sender the letter is refused instead of being invented.

The file belongs outside the repository, profiles.json is in .gitignore.

Layout is fixed

The MCP tools take content only: addresses, date, subject, references, text, signature, enclosures. There are no parameters for margins, spacing, font, image size or position, and unknown fields sent by a client are dropped. Typography is an installation setting (PDF_LETTER_FONT, PDF_LETTER_FONT_SIZE), so every letter of one installation looks identical. The building blocks for a company letterhead, an information block and a footer are still in the library, but they are not reachable through the MCP.

Tools

Tool

Purpose

create_letter

Renders the letter and writes the PDF. Returns path, page count, layout metrics and warnings.

preview_letter

Same rendering without writing a file, for checking the layout.

prepare_signature

Cleans a scanned signature (crop, transparent background, ink colour) and writes a PNG.

get_din5008_spec

Returns the millimetre geometry of a form.

list_locales

Lists the supported languages and their fixed texts.

list_fonts

Lists built-in families and resolves a font name against the installed system fonts.

create_letter

The sender appears only in the small return address line above the recipient. Place and date sit right aligned above the bold subject block, references go directly below the subject.

{
  "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"]
}

Everything except sender, recipient and body is optional. The salutation is derived from the recipient (Frau plus Dr. Erika Mustermann becomes Sehr geehrte Frau Dr. Mustermann,), the date defaults to today, the closing to the locale default.

Body markup

  • Blank line: new paragraph

  • Single newline: line break (set bodyMode to markdown to reflow instead)

  • - item or 1. item: bullet or numbered list

  • **bold**, *italic*

  • \pagebreak on its own line: forced page break

Signature

Two ways, both end up as a real image in the PDF:

  1. Pass the file directly: signature.path plus trim and removeBackground. The scan is cleaned on every render.

  2. Clean it once with prepare_signature and reuse the resulting PNG. Faster and lets you check the result before it goes into a letter.

trim, removeBackground and inkColor need the optional sharp dependency, which is installed by default. A PNG that already has a transparent background works without it.

The image is an overlay: closing, one blank line, printed name stay exactly where they are, and the signature sits on top of that blank line and across the closing, the way a signature is written over "Mit freundlichen Grüßen" on paper. That overlap is the intended result.

Size and position are decided by the renderer, not by the caller. The signature is scaled to roughly the width of the closing line, around 50 mm, capped proportionally at 1.2 times that width and 28 mm in height. There is no parameter for width, height, offset or spacing, so nothing can shift the layout letter by letter.

Verification

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

examples/ holds the German letter, the same letter in English and a debug variant that draws the DIN 5008 zones, so the address field position can be checked against a window envelope. preview_letter reports the same measurements as JSON, plus warnings when the address is too long or does not fit the address field.

License

MIT, see LICENSE. The bundled DejaVu fonts are covered by the Bitstream Vera and Arev licenses.

Available Tools

7 tools
create_letterCreate letter PDFA

Renders a letter as a PDF file in the fixed house layout (DIN 5008 address field, 25 mm writing margin, fold and punch marks, bold subject block). Pass content only, the layout is fixed. The signature image intentionally overlaps the closing line. Returns the absolute file path, the page count, layout metrics and warnings.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesLetter text. Blank lines separate paragraphs, "- " starts a bullet list, "1. " a numbered list, **bold** and *italic* are supported, "\pagebreak" forces a page break.
dateNoISO date (2026-07-24), "today" or free text. Default "today".
marksNoRemark zone above the address, max. 3 lines, e.g. ["Einschreiben"].
placeNoPlace for the "place, date" line.
copyToNo
localeNoLanguage of the fixed texts and date format. Supported: de, en, fr, es, it, nl, pt, pl, tr, da, sv, cs. Regional tags such as "en-US" are accepted. Default "de".
senderNoSender, printed as the small return address line above the recipient. Only needed when no profile is used, a profile always wins.
closingNoDefault is the closing phrase of the locale.
profileNoSender identity, taken from the profile file on this machine (see list_profiles). The profile provides address, return address line and signature image. Use this instead of typing a sender.
subjectNoSubject line, printed without a "Betreff:" label as required by DIN 5008.
metadataNo
dateStyleNoDefault "numeric" (24.07.2026).
overwriteNoOverwrite an existing file instead of adding a counter, default false.
recipientYesRecipient, positioned in the DIN 5008 address field so it shows in the envelope window.
signatureNoSignature below the closing line. The image is scaled and placed by the renderer: it is laid over the blank line above the printed name and deliberately overlaps the closing line, exactly like a signature on paper. That overlap is intended and must not be compensated for.
enclosuresNo
outputPathNoTarget PDF path. Default: PDF_LETTER_OUTPUT_DIR (or the temp directory) plus a name derived from the subject.
salutationNoDefault is the generic salutation of the locale.
returnBase64NoAlso return the PDF as base64, default false.
subjectLinesNoFurther bold lines right below the subject. This is where a normal German letter carries references, e.g. ["Zeichen: 535 B 335D028418", "Kunden-Nummer: 335D028418"].
countryDisplayNoWhen to print the country line, default "auto" (only for foreign recipients).
returnAddressLineNoReturn address line above the recipient. Generated from the sender, pass "" to hide it.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. The description does a strong job: it reveals the fixed house layout (DIN 5008 address field, 25mm margin, fold/punch marks), the intended signature overlap ('The signature image intentionally overlaps the closing line'), and the return format (file path, page count, layout metrics, warnings). This is meaningful behavioral context beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact (three sentences) and front-loaded with the core purpose. Every sentence earns its place: what it renders, the fixed-layout constraint, a notable quirk (signature overlap), and the return value. It is not padded with schema-echo.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a complex tool (22 params, nested objects, no annotations, no output schema), yet the description covers the fixed layout constraint, the signature overlap behavior, and the return payload. The high schema coverage (86%) lets the schema carry the parameter details, and the description compensates for the format/layout context. The main gap is not naming sibling alternatives for when to choose this vs preview_letter, but the description is otherwise thorough for its complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is high at 86%, so the schema documents most parameters well. The description itself does not enumerate individual params (correctly, given coverage), but it does add behavioral semantics around the signature image and layout. Baseline 3 applies given high schema coverage; the description adds some value beyond it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb+resource combination ('Renders a letter as a PDF file') with detail about the layout (DIN 5008, 25mm margin, fold/punch marks, bold subject). It clearly distinguishes from siblings like preview_letter through 'in the fixed house layout' and 'Pass content only, the layout is fixed.' This is specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear usage directive ('Pass content only, the layout is fixed') and notes when a profile should be used vs typing a sender (in the schema, not the description). However, the description does not explicitly state when to use this vs preview_letter, list_profiles, or get_din5008_spec, nor provide exclusion conditions. The context implies usage well but lacks explicit alternative differentiation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_din5008_specGet DIN 5008 geometryB

Returns the millimetre geometry of the layout: address field, remark zone, writing margins, subject position, fold and punch marks.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden. It names the specific geometry elements returned, which gives the agent a reasonable idea of the output scope. However, it doesn't disclose return units nuance (assumes mm is noted in description itself), format, or whether it's language-dependent. For a read-only query tool, this is acceptable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single concise sentence that front-loads the core purpose ('Returns the millimetre geometry of the layout') and then enumerates specifics. No wasted words, appropriately sized for a parameterless query tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (zero params, no output schema), so the description's scope is adequate. However, no output schema exists, so the description is the only source of output information. It lists the geometry components well but could note that 'mm' is the unit (it does mention millimetre), and could mention if values are required for constructing letters with create_letter. Slightly thin for a tool with no output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has zero parameters with 100% schema coverage, meaning there's no schema burden to compensate for. The description meaningfully explains what the returned geometry contains, which is valuable since the agent cannot otherwise predict the output. Baseline for 0 params is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Describes a specific verb+resource (get geometry of DIN 5008 layout) and enumerates the specific geometry elements: address field, remark zone, writing margins, subject position, fold and punch marks. Clear enough to distinguish from siblings, though it doesn't explicitly differentiate from siblings like preview_letter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to call this tool vs alternatives. There's no mention of use cases, prerequisites, or exclusions. While siblings like preview_letter or create_letter clearly differ, the description doesn't explicitly say when to use this instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_fontsList fontsA

Lists the built-in font families and resolves a font name against the installed system fonts, so you can check what create_letter would embed.

ParametersJSON Schema
NameRequiredDescriptionDefault
familyNoFont family or .ttf path to resolve.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions the dual behavior (listing built-ins AND resolving a name against system fonts), which is genuinely useful. However, it doesn't disclose the return format, behavior when family is invalid/not found, or any side effects, though as a read-only listing tool the stakes are relatively low.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One well-formed sentence that conveys purpose and context efficiently with zero waste. It is appropriately front-loaded and compact; no redundant phrasing or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only listing tool with 1 optional parameter, 100% schema coverage, and no output schema, the description is reasonably complete. It covers both behaviors (listing and resolution) and ties to the create_letter use case. The main gap is not describing return values, but the tool's simplicity keeps this from being a major deficiency.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents the family parameter as a font family or .ttf path. The description adds the semantic connection that resolution is against installed system fonts and relates to create_letter embedding, which adds modest value beyond the schema. A baseline 3 is appropriate when the schema carries the parameter documentation load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-list combined with a clear resource (font families) and adds the resolution behavior against system fonts. It distinguishes itself from siblings by tying it to create_letter embedding, though it doesn't explicitly differentiate from other listing tools like list_locales or list_profiles beyond the subject matter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the usage context ('so you can check what create_letter would embed'), which gives some when-to-use guidance. However, it doesn't explicitly state when NOT to use it, mention that the family parameter is optional, or clarify alternatives among sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_localesList localesA

Lists the supported languages together with their fixed texts (salutation, closing, enclosures, page numbering).

ParametersJSON Schema
NameRequiredDescriptionDefault
localeNoReturn the labels of a single locale.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden. It describes this as a read/list operation implicitly through the verb 'Lists', and clarifies the scope of what's returned. However, it doesn't describe return format, whether the optional locale filter changes response shape, or any side effects (though for a list tool these are minimal).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single, information-dense sentence with zero waste. It communicates the subject (languages), the action (lists), and the returned content (fixed texts with enumerated examples).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with one optional parameter fully documented in the schema, the description is adequate. It names the return content (fixed texts) and the subject. It could add a note about the default behavior when no locale is given (all locales vs. all), but with the schema covering the parameter and a list tool's inherent simplicity, this is reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema documents the 'locale' parameter as 'Return the labels of a single locale.' The description doesn't add additional meaning about the locale parameter beyond the schema, but it does contextualize that the full output includes fixed texts, which helps infer the filter behavior. Baseline 3 is appropriate since schema carries the documentation load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clear verb+resource: 'Lists the supported languages' combined with what data is returned (fixed texts like salutation, closing, enclosures, page numbering). Distinguishes from siblings like list_fonts and list_profiles by naming its subject 'locales/languages'. Doesn't explicitly differentiate from all siblings but the resource is clearly unique.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use it (need to see supported languages and their fixed texts), but gives no explicit when-not-to-use or alternatives. It's a simple list tool among create/preview/letter tools, so the context is clear, but no exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_profilesList sender profilesA

Lists the sender profiles configured on this machine. Each profile carries the address and the signature of one person, so create_letter only needs the profile key.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It discloses the machine-local scope, which is a meaningful behavioral trait. However, it doesn't describe the return format, count expectations, or whether profiles are user-managed, leaving the shape of results unspecified.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, each earns its place. The first states the action and scope; the second explains the domain meaning and downstream use. Efficient and front-loaded with the action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless list tool with no output schema, the description covers the essential purpose and downstream coupling well. The only minor gap is not describing the response structure (e.g., list of profile keys/addresses/signatures), but for a zero-parameter, list-only read tool the coverage is strong.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there are no parameter semantics to document. The description focuses instead on the output concept (what a profile entails) and how the output couples to create_letter, which is the appropriate emphasis for a parameterless tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb+resource combination ('Lists the sender profiles configured on this machine'), clearly distinguishing itself from siblings like list_locales and list_fonts. It also explains that each profile carries address and signature, adding domain-relevant detail beyond a generic enumeration.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly signals usage context (listing profiles to obtain a key for create_letter), which orients the agent on why this tool exists in the workflow. However, it does not provide explicit when-to-use vs when-not-to-use guidance or name alternatives, though the relationship to create_letter provides useful context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

prepare_signaturePrepare signature imageA

Cleans up a scanned signature: crops white borders, turns the paper background transparent and optionally recolours the ink. Writes a PNG that can be passed to create_letter as signature.path. Needs the optional sharp dependency.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNoPath to the scan (PNG, JPEG, and with sharp also WebP/TIFF/HEIC).
trimNoCrop uniform borders, default true.
base64NoImage data as base64 or data URL, alternative to path.
inkColorNoRecolour the ink, e.g. "#1a1a1a".
overwriteNo
outputPathNoTarget PNG path. Default: output directory plus "signature.png".
removeBackgroundNoTurn the white background transparent, default true.
backgroundThresholdNoLuminance cutoff, default 0.85.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the transparency burden. It discloses the external sharp dependency requirement, describes the transformation behavior (cropping, transparency, recolouring), and names the output file. It doesn't disclose potential destructive overwrite behavior of the output path beyond implying output, though a boolean 'overwrite' parameter is present. Slightly incomplete but reasonable disclosure for the context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: what the tool does, what it outputs and how it plugs into the pipeline, and the one external prerequisite (sharp). Zero filler, every sentence earns its place, and the most important information (purpose+output) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter tool with no output schema, the description explains the core workflow (scan → clean PNG → create_letter). The sharp dependency note, output path default, and pipeline integration collectively give adequate context. It could mention default behaviors of trim/removeBackground (true) more explicitly, but the schema documents those. Reasonably complete for this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is high at 88%, with most parameters having descriptive text. The description itself adds the key linking insight that the output PNG is intended for create_letter. It doesn't elaborate on parameter interplay (e.g., path vs base64 alternatives), but the schema already documents most parameter meanings well, so the high coverage makes an above-description contribution unnecessary.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (clean up/prepare), the resource (scanned signature), the specific operations (crops white borders, turns background transparent, recolours ink), and the output format (PNG). It also explicitly differentiates from siblings by noting the output 'can be passed to create_letter as signature.path', establishing its role in the pipeline.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear operational context: it processes a scanned signature and produces a PNG for use with create_letter. It mentions the sharp dependency as a prerequisite for additional formats. However, it does not explicitly state when NOT to use it or name direct alternatives among siblings (create_letter consumes the output rather than competing).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_letterPreview letter layoutA

Renders the letter in memory and returns layout metrics and warnings without writing a file. Use it to check whether the address fits the address field or the letter runs onto a second page.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesLetter text. Blank lines separate paragraphs, "- " starts a bullet list, "1. " a numbered list, **bold** and *italic* are supported, "\pagebreak" forces a page break.
dateNoISO date (2026-07-24), "today" or free text. Default "today".
marksNoRemark zone above the address, max. 3 lines, e.g. ["Einschreiben"].
placeNoPlace for the "place, date" line.
copyToNo
localeNoLanguage of the fixed texts and date format. Supported: de, en, fr, es, it, nl, pt, pl, tr, da, sv, cs. Regional tags such as "en-US" are accepted. Default "de".
senderNoSender, printed as the small return address line above the recipient. Only needed when no profile is used, a profile always wins.
closingNoDefault is the closing phrase of the locale.
profileNoSender identity, taken from the profile file on this machine (see list_profiles). The profile provides address, return address line and signature image. Use this instead of typing a sender.
subjectNoSubject line, printed without a "Betreff:" label as required by DIN 5008.
metadataNo
dateStyleNoDefault "numeric" (24.07.2026).
recipientYesRecipient, positioned in the DIN 5008 address field so it shows in the envelope window.
signatureNoSignature below the closing line. The image is scaled and placed by the renderer: it is laid over the blank line above the printed name and deliberately overlaps the closing line, exactly like a signature on paper. That overlap is intended and must not be compensated for.
enclosuresNo
salutationNoDefault is the generic salutation of the locale.
subjectLinesNoFurther bold lines right below the subject. This is where a normal German letter carries references, e.g. ["Zeichen: 535 B 335D028418", "Kunden-Nummer: 335D028418"].
countryDisplayNoWhen to print the country line, default "auto" (only for foreign recipients).
returnAddressLineNoReturn address line above the recipient. Generated from the sender, pass "" to hide it.

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses key behavioral traits: in-memory rendering, no file written, returns layout metrics and warnings (fits address field, second-page detection). However, it doesn't describe return format, pagination behavior details, or what specific warnings/layout metrics are returned beyond the two examples.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero waste. The first states what it does, the second states when to use it. Front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the large 19-param schema with 84% coverage and nested objects, the description is reasonably complete for a preview/validation tool. No output schema exists, but the description at least signals the nature of returns (layout metrics, warnings). Could add the exact set of warnings/metrics, but the tool's purpose as a dry-run check is well covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 84%, so the schema documents most parameters adequately. The description adds modest value referencing 'address field' and 'second page' as the metrics it checks. It doesn't re-explain individual parameters, which is appropriate given high schema coverage. Does not compensate for the ~16% undocumented scope, but baseline 3-4 is warranted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb+resource ('Renders the letter in memory and returns layout metrics and warnings') and clearly distinguishes from siblings by stating it operates 'without writing a file.' It contrasts with create_letter among siblings, making its purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use it: 'Use it to check whether the address fits the address field or the letter runs onto a second page.' This gives concrete scenarios and implies it's a validation step before create_letter, though it doesn't name the alternative tool explicitly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 7 tool updatesv1.0.3
    • First observedcreate_letter
    • First observedget_din5008_spec
    • First observedlist_fonts
    • First observedlist_locales
    • First observedlist_profiles
    • First observedprepare_signature
    • First observedpreview_letter

TDQS

A4/5.0
Disambiguation5/5

Each tool targets a distinct purpose: creating/rendering letters, previewing, signature prep, listing locales/fonts/profiles, and retrieving layout specs. No two tools overlap in responsibility, and preview_letter vs create_letter are clearly differentiated (in-memory check vs file output).

Naming Consistency5/5

All tools follow a consistent verb_noun pattern: list_locales, list_fonts, list_profiles, create_letter, preview_letter, prepare_signature, get_din5008_spec. The verbs are uniform and the noun targets are clear.

Tool Count5/5

Seven tools is a well-scoped set for a letter-generation server. Each tool earns its place: three listing helpers, two render paths, one signature prep, and one spec reference. This is squarely in the ideal 3-15 range.

Completeness4/5

The core workflow is fully covered: discover fonts/locales/profiles, prepare a signature, preview, and create the PDF. The only minor gap is the absence of an explicit validation/strict mode tool or a way to retrieve existing generated letters, but agents can work around these.

Maintenance

ActivitySlowing
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for DACH e-invoicing. Create XRechnung (UBL) and ZUGFeRD 2.3 (Factur-X CII) invoices, validate against EN 16931 rules, extract data from XML, and convert between UBL, CII and JSON formats.
    6
    54
    2
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server for local PDF manipulation including merging, splitting, rotating, watermarking, and text extraction. It works with various MCP-compatible clients and processes PDFs entirely on-device without cloud services.
    11
    17
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server for generating professional PDFs from structured JSON in AI agents like Claude or Cursor, using pure Node.js with embedded fonts and precision text layout.
    6
    31
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bitterdev/pdf-letter-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server