---
name: paperhug
description: Print messages on a family's Paperhug receipt printer through the Paperhug MCP server. Use when a user asks to print, send a note to the kitchen printer, schedule a daily briefing, or check what a household printer has printed.
---

# Paperhug for agents

Paperhug turns Markdown into a paper receipt on a family's kitchen printer. You send text. A person reads paper. Write for that.

## Connect

The Paperhug MCP server speaks Streamable HTTP at `https://<paperhug-host>/mcp`. Authorization is OAuth 2.1 with PKCE. The server publishes its metadata at `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource`, and it accepts Client ID Metadata Documents, so a client needs no pre-registration. On first use the person signs in, picks one household, and approves the scopes you request. Ask for the smallest set.

Cursor, in `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "paperhug": { "url": "https://<paperhug-host>/mcp" }
  }
}
```

Claude Desktop and Claude Code take the same URL as a remote MCP server. Claude Code: `claude mcp add --transport http paperhug https://<paperhug-host>/mcp`.

## Scopes

| Scope | Grants |
| --- | --- |
| `printers:read` | `list_printers`, the `paperhug://printers` resource |
| `messages:read` | `get_message`, `search_messages` |
| `messages:write` | `preview_message`, `send_message`, `cancel_message`. Every print needs this. |
| `schedules:read` | `list_schedules` |
| `schedules:write` | `create_schedule`, `update_schedule`, `cancel_schedule`, `run_schedule` |
| `history:read` | Delivered history older than the current day in `search_messages` |
| `household:profile` | The `paperhug://household` resource: timezone, language, first names. Not in the default set. |

## Tools

| Tool | Scope | Input | Returns |
| --- | --- | --- | --- |
| `list_printers` | printers:read | none | printers with `id`, `name`, `online`, `paper`, `isDefault` |
| `preview_message` | messages:write | `printerId`, `content`, `format` | a preview image and the receipt height, or a render error with line and column |
| `send_message` | messages:write | `printerId`, `content`, `format` (`markdown` default, `html`), optional `sendAt` ISO time, optional `idempotencyKey` | `messageId`, `state: accepted`, optional `occurrenceId` |
| `get_message` | messages:read | `messageId` | state, timestamps, preview |
| `cancel_message` | messages:write | `messageId` | new state |
| `search_messages` | messages:read | `query`, filters for source, printer, state, date range, `cursor` | matches with highlights, next cursor |
| `create_schedule` | schedules:write | `printerId`, `name`, `rule` (`daily` time, `weekly` weekdays and time, or `cron`), `timezone`, `prompt` | schedule with `nextRunAt` |
| `list_schedules` | schedules:read | none | schedules with next run and last state |
| `update_schedule` | schedules:write | `scheduleId` plus fields | updated schedule |
| `cancel_schedule` | schedules:write | `scheduleId` | deleted |
| `run_schedule` | schedules:write | `scheduleId` | one immediate `occurrenceId` |

`send_message` returns `accepted`. That means Paperhug stored and queued the message. It does not mean paper came out. Say "sent to the printer" or "queued", never "printed", unless `get_message` shows `printed`. A printer can be offline for hours. Queued messages never expire.

## Resources and prompts

- `paperhug://printers`: the same list as `list_printers`.
- `paperhug://receipt-guide`: this Markdown guidance with live limits.
- `paperhug://household`: timezone, language, first names. Needs `household:profile`.
- `paperhug://model-policy`: which models the household allows and its budgets.
- Prompts: `daily_briefing`, `love_note`, `reminder`. Each gathers what it needs at invocation, never before.

## Writing a receipt

The paper is 80 mm wide, 576 dots, one color. tm20 typesets a strict Markdown subset and rejects anything else with a source line, column, and hint. Fix the error and resend.

Supported: paragraphs, `#` heading at 18 pt and `##` to `######` at 11 pt bold, emphasis and strong, hard line breaks, inline code and fenced code (no wrapping, over-wide lines reject), lists up to three levels, task lists, block quotes up to three levels, thematic breaks, tables with two or three columns (left or right alignment only), links (printed as italic labels with numbered endnotes), autolinks, footnotes, strikethrough, smart punctuation, and images.

Not supported: raw HTML, math, centered table columns, YAML front matter, definition lists, image size attributes.

Images: standalone PNG or JPEG referenced by a Paperhug asset id, for example `![](asset:01J...)`. Upload with `POST /v1/assets` first or use an id another tool returned. Network URLs in Markdown are rejected. Images are shrunk to the paper width and dithered to one bit.

Limits: 64 KiB of Markdown, 2 MiB per image, 6 MiB of images per message, 6,000 pixels of receipt height. Preview any receipt longer than a screen or with images before sending. A family will hold what you print.

Every receipt ends with a source line that names you as the authorized client. Do not add your own signature.

## HTML

`format: "html"` renders through a headless browser and prints the result as an image. Use it for a designed card, not for text. JavaScript never runs. Scripts, event handlers, frames, forms, and non-HTTP URLs are removed before the browser sees the page. The browser may fetch public web resources, so anything you place in a URL leaves the household; isolation cannot prevent that disclosure. Limits: 256 KiB of HTML, 2,000 nodes, 500 style rules, 20 resource requests, 5 MiB fetched, ten seconds, 6,000 pixels tall, 200 renders per household and 50 per credential each day. A failure comes back as `render_failed` with an `html_` code and a hint. A superadmin can turn HTML off for everyone or for one household.

## Good receipts

- One idea per receipt. A briefing is a heading, three short sections, and a closing line.
- Use the household language from `paperhug://household` when you have the scope, or match the language of the request.
- Names matter. Spell family names as given.
- Dates and times in the household timezone.
- No emoji. The printer has no color and the fonts have no emoji glyphs; tm20 rejects missing glyphs.
- For a schedule prompt, write instructions for a future run, not a finished receipt. The household agent writes the receipt at run time with that day's weather and calendar.
