MCP connector
Post a letter from your AI assistant
Add one URL to Claude, ChatGPT or any MCP client. Your assistant gets your original document ready to print on A4 and post by Australia Post, tracked. You check the preview and pay on our website, so nothing is posted without you.
$10 regular post$20 Express Post
https://unopost.com.au/api/mcpThe same prices as on the website, GST included. No account, sign-in or API key.
Posting from your own code? The connector works from any MCP client or plain HTTP, but each letter is paid for on our website. To post with no one in the loop, use the x402 API.
Connect it
The connector is a remote MCP server over Streamable HTTP. It needs no sign-in, so leave authentication off.
- Claude: open Customize → Connectors, choose Add custom connector, name it Unopost and paste the server URL. In a chat, turn Unopost on from the tools menu.
- ChatGPT: add a custom connector in developer mode with the server URL and no authentication, then turn it on in the chat.
- Claude Code and other clients: add it as a remote HTTP server. Any client that takes custom MCP servers uses the same URL.
claude mcp add --transport http unopost https://unopost.com.au/api/mcp{
"mcpServers": {
"unopost": {
"type": "http",
"url": "https://unopost.com.au/api/mcp"
}
}
}How a letter goes
The assistant confirms the addresses with the user, prepares the letter and gives the user a private review link. The user checks the preview there, enters an email and pays by card. Paying is what posts the letter.
Post this letter by Express Post to Jane Citizen,
12 Example Street, Southbank VIC 3006.
My return address is 1 Sample Road, Carlton VIC 3053.Tools
Assistants call these themselves. Every result from prepare_letter, finish_letter_upload and get_letter_status has reviewUrl, the private page where the user checks the preview and pays, and instructions, which say what to tell the user next.
get_letter_infoPrices, limits, posting times, delivery, tracking and cancelling.TOOLprepare_letterTakes the file the user attached and starts a letter.TOOLcreate_letter_uploadReserves a letter and returns a link to upload the file to.TOOLfinish_letter_uploadAddresses an uploaded letter and starts laying it out.TOOLget_letter_statusPage count, price, preview, payment and posting status.prepare_letter
TOOLprepare_letter
Takes a file reference from the host, such as an attachment in ChatGPT, downloads the original and starts the letter. The file is never retyped, rebuilt or sent as text. Each call creates a new letter, so an assistant calls it once.
Arguments
fileobject · required- The host's reference to the user's original attachment:
download_urlandfile_id, withfile_nameandmime_typeif known. fileNamestring · optional- The file's name with its extension, such as
letter.pdf. Only needed whenfile.file_nameis missing. recipientAddress · required- Who the letter goes to, as the user confirmed it. In Australia unless
serviceisinternational. senderAddress · required- The user's return address, printed on the envelope. It can be in any country.
servicestring · optionalexpress(the default), flat in a B4 envelope;regular, folded into a DL envelope, up to 12 pages; orinternational, signed for on delivery.signatureboolean · optional- Signature on delivery, $6 extra in Australia. Regular post with it goes by Registered Post.
duplexboolean · optional- Print double-sided. Statutory declarations are always printed single-sided.
monoboolean · optional- Print in black and white. Colour stays colour by default, at no extra cost.
stapleboolean · optional- Staple the pages once in the top-left corner. Only for documents of up to 12 pages; a longer one is rejected when it is priced. Defaults to false.
foldboolean · optional- Fold an Express Post or international letter of up to 12 pages into a smaller envelope.
preparedForstring · optional- Only when you write for a business to one of its clients: the business's name, up to 60 characters. The pay page shows it as what the assistant told us, not as checked, and names like Unopost, Australia Post, a bank or a government agency are refused.
notifyEmailstring · optional- With
preparedFor: the business's email. It gets a copy of every email about the letter, from payment to delivery, and the customer sees this address before paying. customerEmailstring · optional- The paying customer's email, if you have it. The pay page starts with it filled in; tracking emails go to it.
Address
name, line1 and suburb are required; names and lines take up to 40 characters. In Australia the postcode sets the state. Overseas, add country, and a Chinese mobile number in phone for a letter to China.
namestring · required- The person's full name.
companystring · optional- A business or organisation.
line1string · required- The street address, or a PO Box such as
"PO Box 123". line2string · optional- A second address line.
suburbstring · required- The suburb or town.
statestring · optional- Leave it out in Australia: the postcode sets it. If given, one of
ACT,NSW,NT,QLD,SA,TAS,VICorWA, matching the postcode. Overseas, the region, if the country uses one. postcodestring · optional- Four digits, required in Australia. Overseas, the postal code, if the country uses one.
countrystring · optional- Leave it out for Australia. Otherwise the country's name in English. The recipient can be overseas only with
serviceset tointernational. phonestring · optional- Only for a recipient in China: their Chinese mobile number, which China Post needs.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "prepare_letter",
"arguments": {
"file": {
"download_url": "https://files.example.com/letter.pdf",
"file_id": "file_abc123",
"file_name": "letter.pdf",
"mime_type": "application/pdf"
},
"recipient": {
"name": "Jane Citizen",
"line1": "12 Example Street",
"suburb": "Southbank",
"postcode": "3006"
},
"sender": {
"name": "Sam Sender",
"line1": "1 Sample Road",
"suburb": "Carlton",
"postcode": "3053"
},
"service": "express"
}
}
}{
"jobId": "019d7a7f-a183-752d-9b3b-11511179033b",
"reviewUrl": "https://unopost.com.au/pay?job=019d7a7f-a183-752d-9b3b-11511179033b",
"currency": "AUD",
"status": "CONVERTING",
"service": "express",
"instructions": "The letter is being laid out, usually for a few seconds. Then give the user reviewUrl to check the preview, enter an email and pay. Nothing is posted until payment. …"
}Upload the file yourself
TOOLcreate_letter_upload → finish_letter_upload
For clients that can read the user's file and make an HTTP request, but whose host has no file references. create_letter_upload takes the file name and returns uploadUrl, which expires in 5 minutes. PUT the original bytes to it, then call finish_letter_upload with the jobId and the same letter fields as prepare_letter.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/octet-stream" \
--data-binary @letter.pdfget_letter_status
TOOLget_letter_status
Reports where a letter is, with the final pageCount and costCents once it's laid out. A letter usually takes a few seconds. Check at most every 5 seconds.
{
"jobId": "019d7a7f-a183-752d-9b3b-11511179033b",
"reviewUrl": "https://unopost.com.au/pay?job=019d7a7f-a183-752d-9b3b-11511179033b",
"currency": "AUD",
"status": "CONVERTED",
"pageCount": 3,
"costCents": 2000,
"previewUrl": "https://unopost.com.au/preview/019d7a7f-a183-752d-9b3b-11511179033b/letter.pdf?Expires=...&Signature=...",
"service": "express",
"instructions": "Ready: give the user reviewUrl to check the preview, enter an email and pay by card. The letter is posted only once it's paid for. pageCount and costCents (AUD cents) are final."
}{
"jobId": "019d7a7f-a183-752d-9b3b-11511179033b",
"reviewUrl": "https://unopost.com.au/pay?job=019d7a7f-a183-752d-9b3b-11511179033b",
"currency": "AUD",
"status": "FAILED",
"error": "document has more than 80 pages",
"instructions": "Not posted, and nothing was charged. The document has more than 80 pages. Suggest splitting it into separate letters of up to 80 pages each. …"
}get_letter_info
TOOLget_letter_info
Current prices in AUD cents, the pages each price covers, page and file limits, and plain-language answers about posting times, delivery, tracking and cancelling. Assistants use it to answer questions before preparing anything.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_letter_info",
"arguments": {}
}
}Limits
pages- Up to 80 pages per letter. Split a longer document into separate letters.
regular- Regular post, and any folded letter, takes up to 12 pages. Longer letters go by Express Post, flat.
size- Up to 50 MB per file.
files- PDF, Word (.doc, .docx), JPEG or PNG. Word documents are laid out on A4.
letter- One file per letter through the connector. The website takes up to 10.
rate- 200 letters an hour from each AI host.
Statuses
CREATED- Reserved, waiting for its file.
CONVERTING- Being laid out.
CONVERTEDAWAITING_PAYMENT- Ready for the user to check and pay at
reviewUrl. PAIDPAYINGSENDINGRETRYINGMANUAL_CHECK- Paid. Letters paid for by 2:30pm Melbourne time on a business day are posted that day.
POSTEDUNDELIVERED- Lodged with Australia Post. The tracking number has been emailed to the user.
DELIVERED- Australia Post's tracking shows it delivered.
FAILED- Not posted.
errorsays why, andinstructionswhat to do next. A paid letter is refunded in full. PAYMENT_EXPIRED- Not paid for in time. Its document has been deleted.
REFUNDED- Cancelled or couldn't be posted, and refunded to the card.
Errors
A tool that fails returns an error result whose text says what went wrong and what to do, written for the assistant. There are no error codes, and we may reword the messages, so act on the kind of error, not its exact words.
A tool never charges or posts, so an error never costs the customer anything. But once an error names a job, that letter exists: check it with get_letter_status rather than preparing a second one.
arguments- An argument is missing or wrong: an address the user should confirm, options that don't go together, an unsupported file type, a refused
preparedForor a malformed email. The message names it. Fix it and call again; nothing was created. file- The original file couldn't be fetched from the host: the link expired, was refused, was too slow or redirected too often, points somewhere private, or the file is empty or over 50 MB. Nothing was posted. Get a fresh file reference, or use
create_letter_upload; never send a text copy instead. job …- The message starts
job …:when the letter was created but a later step failed. Callget_letter_statuswith that job ID, thenfinish_letter_uploadif it's still waiting for its addresses. Don't prepare another letter. rate limit- Too many letters from this AI host this hour, or the connector's limit for the day is reached. Don't retry in a loop: tell the user to try later, or to send it on the Unopost website.
paused- We've paused new letters for a while; letters already under way carry on. Try again later.
not found- No letter has that
jobId, or its upload expired after 24 hours. Use only a job ID Unopost returned to this user, and start again if it expired. server- Something went wrong on our side:
Unopost API returned HTTP 5xx. Wait a few seconds and try once more. FAILED- A letter that can't be printed isn't a tool error:
get_letter_statusreturnsFAILEDwitherrorand plaininstructions, such as splitting a document over 80 pages or removing a password.
Payment and privacy
- It never pays or posts. The connector returns no payment link. The user pays only on the website, after seeing the preview.
- The original file, unchanged. Files never travel inside MCP messages, and are never replaced with text.
- Private links. A job ID is the only key to a letter, so assistants keep it and
reviewUrlto the user. - Cancel before printing. A paid letter can be cancelled for a full refund from
reviewUrluntil we start printing it. - Deleted after posting. Documents are deleted once a letter is posted, and an unpaid letter's after 24 hours.
Webhooks? Use an inbox
The connector has no webhooks. Instead, give the assistant a notifyEmail at an inbox your software reads. Every email about a letter comes from notifications@unopost.com.au and carries the letter in its headers, so a mail service that runs code on incoming mail, such as Amazon SES, Postmark, Mailgun or SendGrid, can act on each update as it arrives.
- Point
notifyEmailat an address your mail service receives, such asletters@yourbusiness.com.au. - Accept only mail from
notifications@unopost.com.authat passes DMARC, and drop the rest. - Read the headers, not the wording, which can change. Drop an
Unopost-Event-Idyou've already seen.
Headers
Unopost-Letter-Id- The letter's
jobId, as the connector returned it. Unopost-Event- What happened:
receipt,posted,tracking,retrying,delayed,awaiting-collection,delivered,cancelled,failed,refundedorrefunded-printed. Unopost-Event-Id- The same for the same news however often it's sent, so you can drop repeats.
Unopost-Letter-Status- The letter's status after it:
TO_POST,POSTED,DELAYED,AWAITING_AT_COLLECTION,DELIVERED,CANCELLEDorREFUNDED. Unopost-Tracking-Number- The Australia Post tracking number, once the letter is posted.
Unopost-Copybusinesson the copy a business gets; not on the customer's own email.
From: Unopost <notifications@unopost.com.au>
Unopost-Letter-Id: 019d7a7f-a183-752d-9b3b-11511179033b
Unopost-Event: tracking
Unopost-Event-Id: evt_3f9a1c0b7e2d4a6b8c1d0e2f
Unopost-Letter-Status: POSTED
Unopost-Tracking-Number: 33LQV507012301000935005
Unopost-Copy: businessexport const handler = async (event) => {
const { mail, receipt } = event.Records[0].ses;
const { from } = mail.commonHeaders;
const fromUs = from.length === 1 && /(^|<)notifications@unopost\.com\.au>?$/i.test(from[0]);
// DMARC, not DKIM alone: only a DMARC pass means unopost.com.au signed it.
if (!fromUs || receipt.dmarcVerdict.status !== 'PASS') return;
const header = name =>
mail.headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value;
await recordUpdate({
letterId: header('Unopost-Letter-Id'),
event: header('Unopost-Event'),
eventId: header('Unopost-Event-Id'), // drop one you've seen
status: header('Unopost-Letter-Status'),
trackingNumber: header('Unopost-Tracking-Number'),
});
};Copies start once the customer pays, so nothing arrives for a letter that's never paid for: check get_letter_status until then. The customer's own emails carry the same headers. We may add headers, but never rename or remove these.
Discovery
Agents can find the connector without being told. It's listed in our AI catalog, which points to its MCP server card.
- AI catalog
/.well-known/ai-catalog.json - MCP server card
/.well-known/mcp/server-card.json
Pricing
| Item | Price |
|---|---|
| Regular post, folded to fit a letterbox: up to 12 pages | $10 |
| Registered post, regular post signed for on delivery: up to 12 pages | $16 |
| Express Post, flat in a B4 envelope: 20 pages included, then $0.30 for each extra page | $20 |
| Express Post with signature on delivery: 20 pages included, then $0.30 for each extra page | $26 |
| Tracking, colour, double-sided or black-and-white printing, and stapling | Free |
Every letter is tracked. The final price depends on the page count, which is known once the letter is laid out.
Letters prepared through the connector are covered by our Terms and Privacy policy, like any other.