Content
# telex
A small message broker with a postal theme, spoken over [MCP](https://modelcontextprotocol.io). Agents connect as MCP clients, mail **letters** to a **post office**, and poll their mailbox to collect what's waiting. Nothing fancy, just four tools and a signed postmark.
## Why the postal metaphor?
Because a plain message broker is boring. Here you don't send a message, you mail a letter. It has a `sender_address` and a `recipient_address`. When the post office handles it, it stamps a **postmark** on it — a real Ed25519 signature, so the recipient can prove where the letter came from and that nobody tampered with it.
You also can't spam the place. Every sender gets a book of **stamps** (a rate limit). Send too fast and you run out, and the office turns you away until your stamps refill.
Post offices are isolated. `berlin` and `hamburg` don't share mailboxes, keys, or stamp counts. Point clients at different offices and they never see each other's mail.
## Run it
```
go run ./cmd/telex
```
Starts an MCP server over streamable HTTP on `:1456`. Point any MCP client at `http://localhost:1456`.
## Authentication
Set `TELEX_TOKEN` to require a bearer token on every request:
```
TELEX_TOKEN=some-long-secret go run ./cmd/telex
```
Clients then send `Authorization: Bearer some-long-secret`. Anything without a valid token gets `401`. If `TELEX_TOKEN` is unset the server runs open (with a warning) — fine for local dev, not for anything exposed.
This is a single shared token: it gates access to the whole post office. It does **not** yet tie a caller to an identity, so it can't stop an authenticated client from putting any `sender_address` on a letter or reading someone else's mailbox. Per-identity tokens (no sender spoofing, own-mailbox-only reads, per-office access) are the next step.
## Tools
Every tool takes an optional `office`. Leave it out and you use the `default` office.
- **send_letter** `{office?, sender_address, recipient_address, content}` — mails a letter. The office stamps a signed postmark and drops it in the recipient's mailbox. Returns the postmark. Errors if you're out of stamps or the mailbox is full.
- **check_mailbox** `{office?, address}` — collects every letter waiting for `address` and empties the box. This is how you receive; poll it.
- **office_key** `{office?}` — returns the office's Ed25519 public key (base64), for verifying postmarks yourself.
- **verify_postmark** `{office?, sender_address, recipient_address, content, stamped_at, signature}` — checks a postmark signature for you and returns whether it's valid.
Letters wait in the mailbox (buffered, up to 100) until collected, so the recipient doesn't have to be listening at the exact moment a letter is sent.
## Postmarks
A postmark signs these fields, joined by newline (`\n`), in this order:
```
sender_address
recipient_address
content
office
stamped_at
```
`stamped_at` is a unix-nano integer. Verify with the office's public key — either yourself via `office_key`, or by handing the fields to `verify_postmark`.
## Layout
```
cmd/telex the MCP server and tool wiring
internal/postal letters, postmarks, stamps, offices
```