SendLetter MCP server
online · 100% uptimeeu.sendletter/sendletter·v1.0.0Send real, printed letters by post across Europe. Requires a free account; quote before sending.
0 stars
Reviews
Write oneNobody has reviewed SendLetter yet.
If you have run it, two minutes of your experience saves the next person an afternoon.
SendLetter tools
Tool list not cached yet. `describe` through the gateway fetches it live.
Public scan report
scanner v0.1.9 · 2026-09-23 · same rubric, same numbers if you re-run it
- –Code scanremote-only server, no package to scann/a
- Live reliabilityremote reachable in 459ms (auth required)20/20
- –Tool poisoningtools not inspected (endpoint requires auth); not countedn/a
- Auth qualityOAuth resource metadata advertised on 40115/15
- Maintenancelast push 17 days ago15/15
- Maintainer identitynamespace and repository owner differ; GitHub account older than a year; website matches verified namespace7/10
How SendLetter compares
Against every graded MCP server, from our own scans and uptime checks. Updated after each scan run.
- Safety score
- 95/100
- higher than 97% of 48,255 servers
- Uptime
- 100%
- of our recent checks; the typical remote server answers 100%
- Response time
- 491 ms
- faster than 30% of 30,031 servers
Install SendLetter in Claude Code, Cursor or VS Code
claude mcp add --transport http sendletter https://sendletter.eu/api/mcp
What the publisher says
From the SendLetter repository's README, as published. We do not edit it. Read it on GitHub
sendletter
Send a real letter — printed, folded, franked and handed to the post — from Node.
npm install sendletterimport { SendLetter } from 'sendletter'
const sendletter = new SendLetter(process.env.SENDLETTER_API_KEY!)
const input = {
idempotencyKey: 'invoice-2026-0042-reminder-1',
sender: {
company: 'Twilper',
name: 'Gert Snijder',
street: 'Merelstraat',
number: '64',
postalCode: '8916 AX',
city: 'Leeuwarden',
country: 'NL',
},
recipient: {
name: 'Jan de Vries',
street: 'Keizersgracht',
number: '123',
postalCode: '1015 CJ',
city: 'Amsterdam',
country: 'NL',
},
text: 'Beste heer De Vries,\n\nBijgaand de herinnering voor factuur 2026-0042.',
}
const prepared = await sendletter.prepare(input)
console.log(prepared.id, prepared.pages, prepared.totalCents)
const pdf = await sendletter.download(prepared.id)Show the PDF and exact total to the user. After approval, use the same input and key:
const letter = await sendletter.send({ ...input, expectedTotalCents: prepared.totalCents })
console.log(letter.id, letter.status, letter.totalCents)Get a key at sendletter.eu. Keys starting sktest post nothing, charge nothing, and still run the whole status chain, so you can build against the real thing.
Sending
Give the content exactly one way: text, document (rich text), file (base64) or fileUrl. Two is refused rather than guessed at, because the wrong document in a postbox cannot be recalled.
// An invoice you already have as a PDF.
await sendletter.send({
sender,
recipient,
file: { name: 'invoice.pdf', contentBase64: pdf.toString('base64') },
product: 'registered', // 'standard' | 'priority' | 'registered'
colour: true,
idempotencyKey: `invoice-${invoice.id}`,
})Send an idempotencyKey on anything that can be retried. A repeat with the same key returns the original letter instead of a second envelope. That single field is what makes a retry after a network timeout safe, and a timeout says nothing about whether the letter was accepted.
Reading
await sendletter.get(id) // one letter
await sendletter.list({ status: 'posted' }) // one page
await sendletter.cancel(id, 'order withdrawn') // while it is still cancellable
await sendletter.download(id) // the PDF as printed
await sendletter.download(id, { proof: true }) // proof of posting
for await (const letter of sendletter.all({ mode: 'live' })) {
// walks every page; you never hold the cursor
}Invoices and credit notes
Every paid live letter receives its invoice number at payment time. Test letters never consume the statutory series. A full refund keeps that invoice and adds a separately numbered negative credit note.
const page = await sendletter.listInvoices()
await writeFile('invoice.pdf', await sendletter.downloadInvoice(page.data[0].id))
if (page.data[0].creditNote) {
await writeFile(
'credit-note.pdf',
await sendletter.downloadCreditNote(page.data[0].creditNote.id),
)
}Checking before you spend
const check = await sendletter.validateAddress(recipient)
if (!check.valid) console.log(check.problems) // answers, does not throw
const quote = await sendletter.quote({ destination: 'DE', pages: 3 })validateAddress returns a bad address rather than throwing: a wrong postcode is the successful outcome of asking. supported: false is the one that cannot be fixed by editing the address — we do not carry to that country.
Errors
Everything the API refuses becomes a SendLetterError with a code to branch on.
import { SendLetterError } from 'sendletter'
try {
await sendletter.send({ sender, recipient, text })
} catch (error) {
if (!(error instanceof SendLetterError)) throw errorShortened. The full README is on GitHub.
Nothing above is checked by us. What we check is on the safety report.
SendLetter: common questions
- Is SendLetter MCP server safe?
- Yes, by our scan: it is graded A (95/100). Read the SendLetter safety report
- How do I install SendLetter?
- It runs remotely at sendletter.eu. Add it to Claude Code, Cursor, VS Code or Claude Desktop with the snippets above, or call it through the mcp.market gateway without installing anything.
- Does SendLetter need an API key?
- No key to paste: it signs you in with OAuth when your client connects.
- Is SendLetter maintained?
- The last commit was 59 days ago (2026-09-06). The latest release is v1.0.0.
- Is SendLetter up?
- 100% of our last 28 checks got an answer. We check remote servers about four times a day.
- How does SendLetter compare with other MCP servers?
- safety score 95/100 (higher than 97% of 48,255 servers); uptime 100% (of our recent checks; the typical remote server answers 100%); response time 491 ms (faster than 30% of 30,031 servers). Full comparison.