Skip to main content
Glama
s04

phomemo

by s04

phomemo

Print on a Phomemo M02 Pro pocket thermal printer from your computer, without the phone app. Includes a command-line tool and an MCP server, so Claude and other AI agents can print cards, checklists and pictures for you.

  • Markdown in, neat cards out: titles, bullets, checkboxes, numbered lists.

  • Pictures are scaled to the paper and dithered for thermal printing.

  • Print jobs you can list, cancel (cleanly, between blocks) and reprint.

  • Waits for the printer to confirm that each card actually printed.

  • Reads battery, paper, lid and temperature.

  • Runs locally over Bluetooth LE on macOS and Linux (and in principle Windows, via bleak).

Supported printers

Model

Status

M02 Pro

Tested: printing, cancel, print-complete signal, status

M02S

Same protocol and resolution as the M02 Pro; untested

M02, T02

Same protocol at 203 dpi; untested

Other Phomemo families (M110, M04, D30, …) use different protocols and aren't supported yet. See Contributing.

Paper: 53mm-wide continuous rolls (e.g. 53mm × 6.5m). The print head covers the middle 48mm (576 dots at 300 dpi).

The M02 Pro's USB-C port only charges. It carries no data, so Bluetooth is the only way to print.

Related MCP server: Memobird MCP Server

Install

uv tool install git+https://github.com/s04/phomemo
# or: pipx install git+https://github.com/s04/phomemo

Requires Python 3.11+.

Use

Turn the printer on and close the Phomemo phone app, because the printer accepts only one connection at a time.

phomemo scan                                  # find printers nearby
phomemo "# Groceries" "- [ ] oat milk" "- [ ] bread"
echo "# Idea" | phomemo                       # from stdin
phomemo -f notes.md                           # from a file
phomemo --preview -f notes.md                 # save a PNG instead of printing
phomemo image photo.jpg                       # print a picture
phomemo status                                # battery, paper, lid, temperature

Card format

# Title                 ← every "# " starts a new card
## Heading
A paragraph of text.
- bullet
1. numbered
- [ ] todo
- [x] done
> aside
---                     ← also starts a new card

The printable width is 48mm (about 25 characters per line), so short cards work best.

Jobs

phomemo jobs                     # recent jobs, status and progress
phomemo cancel                   # stop everything queued or printing
phomemo cancel 0923-1651         # stop one job (any unique id prefix)
phomemo reprint                  # print the last job again
  • Ctrl-C cancels cleanly; press it twice to force quit.

  • Cancelling stops between image blocks (at most about 2cm of paper) and feeds the paper out. The printer is left ready for the next job.

  • Cancelling works across processes: phomemo cancel stops a print an AI agent started.

  • Only one job talks to a printer at a time. The others wait as queued.

  • Job statuses:

    • done: the printer confirmed every card printed.

    • unconfirmed: all data was sent but the printer never confirmed. Check the output; a low battery is the usual cause.

    • failed, cancelled.

Job history lives in ~/.local/state/phomemo/jobs (override with PHOMEMO_STATE).

MCP server (Claude and other agents)

phomemo mcp                          # stdio
phomemo mcp --http 127.0.0.1:8765    # streamable HTTP at /mcp

Tools: print_cards, preview_cards (returns images, so the agent can check the layout first), print_picture, printer_status, list_print_jobs, cancel_print, reprint, list_printers. The print tools wait up to 15 seconds. A longer print keeps running in the background and the tool returns its job id.

Claude Code

claude mcp add phomemo -s user -- phomemo mcp

Claude Desktop (claude_desktop_config.json):

{ "mcpServers": { "phomemo": { "command": "phomemo", "args": ["mcp"] } } }

Use the full path from which phomemo if the app can't find the command.

Configuration

Optional. Without a config file you get one printer, m02pro, found automatically. phomemo config shows where the file goes, with an example:

default = "desk"

[printers.desk]
model = "m02pro"
# address = "…"    # from `phomemo scan`; skips discovery, picks one of several printers
# feed = 3         # blank lines after each card

Driver options are listed in src/phomemo/drivers/m02.py.

Troubleshooting

  • "not found over Bluetooth": turn the printer on and close the Phomemo app. On macOS, the app running phomemo (Terminal, iTerm, Claude…) needs Bluetooth access under System Settings → Privacy & Security → Bluetooth.

  • The light blinks fast: the paper is out, the printer is too hot, or the battery is low. phomemo status tells you which.

  • It won't charge from a USB-C charger: use a 5V USB-A charger with an A-to-C cable. Some USB-C chargers never switch on power for this printer. Phomemo warns that chargers above 5V can damage it.

  • Photos look muddy: pictures are contrast-stretched and brightened before dithering, but thermal paper suits strong contrast. Bold images print best.

Thermal paper

Most thermal paper contains BPA or BPS, and both are absorbed through the skin. "BPA-free" usually means BPS. If you'll handle the prints a lot, look for phenol-free paper.

How it works

The protocol was reverse-engineered by others (see Credits). What this project verified on a real M02 Pro, including the print-complete signal and the status replies, is in PROTOCOL.md.

src/phomemo/
  cards.py        Markdown → cards
  render.py       cards / pictures → grayscale images at printer width
  drivers/m02.py  M02 family: raster encoding, Bluetooth transport, status
  jobs.py         job records, per-printer queue, cancel, reprint
  api.py          shared by the CLI and the MCP server
  cli.py          `phomemo`
  mcp_server.py   `phomemo mcp`

Contributing

Issues and pull requests are welcome, especially reports from M02S, M02 and T02 owners (does printing work, and does phomemo status answer?).

uv sync
uv run pytest

⚠️ Don't probe unknown 1F 11 NN commands. Sweeping opcodes above 0x14 bricked an M02X. Stick to documented commands.

Credits

The protocol knowledge comes from vivier/phomemo-tools, ryo-endo/phomemo-printer, theacodes/phomemo_m02s and sgrankin/phomemo. This project re-implements it and contains no code from those projects.

Not affiliated with Phomemo.

License

MIT

Available Tools

8 tools
cancel_printA

Cancel a print job by id (or unique id prefix). Without an id, cancels every unfinished job. A thermal print stops after the current block and feeds the paper out.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations, the description carries the full behavioral burden. It does disclose a real behavioral trait — a thermal print stops after the current block and feeds paper out — and that the id-less call cancels everything unfinished. It does not state whether cancellation is reversible, whether it requires the printer to be idle, or any confirmation semantics for the destructive branch.

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 short sentences with zero filler, front-loading the primary action and then the no-id scope and physical side effect in priority order.

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?

An output schema exists, so return values need not be explained. For a destructive, annotation-free mutation the description covers scope and physical behavior, but says nothing about reversibility or prerequisites, which an agent calling a cancel tool would want.

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 description coverage is 0%, so the description must compensate, and it does: job_id accepts a full id or a unique id prefix, and null/absent means cancel all unfinished jobs. Only the exact id format and prefix-ambiguity handling are left unstated.

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?

States a specific verb (cancel) and resource (print job), plus the key edge case that omitting the id cancels every unfinished job. It does not name or contrast with any sibling such as list_print_jobs, which is how an agent would discover ids, so it falls short of full sibling differentiation.

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?

Usage is implied by the two modes described (cancel one by id/prefix, or cancel all). There is no explicit when-to-use guidance, no mention of how to obtain a job id (e.g., list_print_jobs), and no caution about the destructive all-jobs case.

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

list_printersB

List configured printers.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.1/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full behavioral burden, and it discloses nothing beyond the basic operation. It does not say whether this requires printer configuration/permissions, whether output is paginated, or how it behaves when no printers are configured.

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?

A single short sentence that is front-loaded and wastes no words. It is efficient, though it errs toward under-specification rather than excessive brevity.

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?

An output schema exists, so return values need not be explained, and the read-only nature is implied by 'List'. Still, for a tool sitting among many print-related siblings with no annotations, the description does not do enough to route the agent correctly.

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 takes zero parameters, so the schema is trivially complete and the description has no parameter semantics to document. Baseline 4 applies for a parameterless tool.

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?

States a specific verb (List) and resource (configured printers), so the agent immediately knows the operation. However, it does nothing to distinguish itself from close siblings such as printer_status or list_print_jobs, which the agent must infer from names alone.

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 use this versus printer_status (single printer detail) or list_print_jobs (queued work). The agent is left to infer the distinction from tool names, with no stated context or exclusions.

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

list_print_jobsA

Recent print jobs, newest first: id, status (queued, printing, done, unconfirmed, cancelled, failed), progress and a summary. "done" on a thermal printer means the printer confirmed the cards came out; "unconfirmed" means the data was sent but the printer never said so, so ask the user to check.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior4/5

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

With no annotations, the description carries the full burden and delivers real behavioral context: result ordering, the field set, the full status enum, and the crucial domain distinction between 'done' (printer confirmed cards emerged) and 'unconfirmed' (data sent, no confirmation). It omits that the call is read-only and says nothing about the limit/pagination behavior.

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?

Front-loaded with the return shape, then the status semantics that actually require explanation. Every sentence earns its place; it is slightly dense around the status enum but not padded.

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?

An output schema exists, yet the description usefully supplements it with the interpretation of 'done' vs 'unconfirmed', which is the piece an agent most needs to avoid misreporting. The one real hole is the undocumented 'limit' parameter, otherwise the definition is adequate for the tool's complexity.

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

Parameters2/5

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

Schema description coverage is 0% for the single 'limit' parameter, and the description never mentions limit, its default of 10, or whether it caps the returned list. For a one-param tool with no schema documentation, the description should have compensated and does not.

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 states the resource (print jobs) and the ordering (newest first) and enumerates the returned fields, so an agent knows exactly what it gets back. It implicitly distinguishes itself from siblings like printer_status or list_printers, though it never names them or uses an explicit verb like 'list'.

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?

Usage is implied by the content — this is the tool for reviewing recent print jobs — but there is no explicit statement of when to reach for it versus printer_status or list_printers. It does give one actionable directive ('ask the user to check' for unconfirmed jobs), which is a genuine usage cue.

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

preview_cardsA

Render cards exactly as they would print, without printing. Returns images.

Card format (Markdown subset). Each # Title starts a new card; --- also starts one. Inside a card: ## Heading, plain paragraphs, - bullets, 1. numbered, - [ ] todo, - [x] done, > aside. Keep cards short: one thought per card, a title plus up to ~6 lines. The paper is only ~48mm wide (~25 characters per line), so prefer short words and lines.

ParametersJSON Schema
NameRequiredDescriptionDefault
printerNo
markdownYes

TDQS

A4.1/5.0
Behavior4/5

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

No annotations exist, so the description carries the full burden, and it does disclose the key traits: this is a non-destructive preview that produces images rather than triggering hardware. It does not mention whether a specified printer changes the rendered output, nor any permissions or rate constraints.

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?

Purpose and return type are front-loaded in the first two sentences, and the follow-on material is functional documentation of the markdown subset, not filler. It is dense but each clause serves the required-parameter gap left by a 0%-coverage schema.

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 two-parameter preview tool with no output schema or annotations, the description covers the essential behavior (renders, does not print, returns images) and the input format in detail. The remaining gap is the unexplained 'printer' parameter and its effect on the preview.

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 0%, so the description must compensate. It thoroughly documents the required markdown parameter's syntax (headings, bullets, todos, blockquotes, '---' behavior) and the paper's 48mm/~25-character line limit, but never explains the optional 'printer' parameter or how it affects rendering.

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?

States a specific verb (render) and resource (cards) with an explicit scope qualifier: 'exactly as they would print, without printing.' This directly distinguishes it from the sibling print_cards, and 'Returns images' pins down the output medium.

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?

'Without printing' clearly signals the preview-before-print use case, which is enough to route an agent away from print_cards. However, no sibling is named explicitly and no when-not condition (e.g. don't use for final output) is stated.

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

printer_statusA

Check a printer before printing: battery_percent, paper, cover and temperature. Warn the user when the battery is low (under ~20%) before long prints.

ParametersJSON Schema
NameRequiredDescriptionDefault
printerNo

TDQS

A3.6/5.0
Behavior3/5

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

With no annotations, the description carries the full burden. It discloses the checked attributes and a useful behavioral rule (warn at ~20% battery before long prints), but says nothing about read-only nature, printer-disconnected/error behavior, or response format beyond the field list.

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 tight sentences, front-loaded with the action and the inspected fields, then the conditional warning. Every clause earns its place with no 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?

With no output schema, the description usefully enumerates the fields returned, and the battery-threshold guidance covers the key agent-facing behavior. The gap is the ambiguous 'printer' parameter, but overall it is sufficient for a simple one-param status check.

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

Parameters2/5

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

The single 'printer' parameter has 0% schema description coverage and defaults to null, yet the description never explains what value identifies a printer (name, id, index) or that omitting it targets the default printer. The description does not compensate for the coverage gap.

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?

States a specific verb ('Check') and resource ('a printer') and enumerates what is inspected (battery_percent, paper, cover, temperature). This distinguishes it in spirit from list_printers/list_print_jobs, though no sibling is named explicitly.

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?

'Check a printer before printing' gives clear timing/context for use, and the low-battery warning is scoped to 'long prints'. No alternatives or when-not-to-use conditions are named, so it does not reach a 5.

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

reprintB

Print a previous job again, optionally on a different printer. Default: the last job.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idNolast
printerNo

TDQS

B3.3/5.0
Behavior2/5

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

With no annotations, the description carries the full behavioral burden and falls well short: it does not say whether reprint creates a new job record, requires the printer to be online or known, what happens if job_id is invalid, or whether the action is reversible. The only behavioral disclosure is the default-to-last-job behavior, which largely restates the schema default.

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 short sentences, front-loaded with the core action and followed by the default behavior. Nothing is redundant and every clause carries information.

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 two-parameter action tool this is a reasonable minimum, covering purpose, default, and the optional printer override. But with no annotations and no output schema, it omits error behavior, side effects, and printer/job prerequisites, leaving the agent without enough to handle anything beyond the happy path.

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 0%, so the description must compensate, and it partially does: it explains that job_id selects a previous job (default: last) and that printer is an optional override. It adds no format details for job_id, no indication that printer should come from list_printers, and no clarification of what a null printer means.

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?

States a specific verb ('Print ... again') and resource ('a previous job'), and the phrase 'previous job' implicitly separates it from new-print siblings like print_cards and print_picture. It does not, however, name or contrast with any sibling explicitly, so the differentiation is inferential rather than stated.

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?

It supplies the key usage fact that no job_id means 'the last job' and that a different printer may be targeted, which tells the agent when the call is appropriate. There is no guidance on when not to use it (e.g., when the original job was cancelled, or when a fresh print should be issued instead) and no alternatives named.

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.

  1. 8 tool updatesv0.1.0
    • First observedcancel_print
    • First observedlist_print_jobs
    • First observedlist_printers
    • First observedpreview_cards
    • First observedprint_cards
    • First observedprint_picture
    • First observedprinter_status
    • First observedreprint

TDQS

A3.7/5.0

Scored across 8 tools

Disambiguation5/5

Each tool targets a clearly distinct action: printing (print_cards, print_picture), rendering (preview_cards), cancelling (cancel_print), reprinting (reprint), and read-only queries (list_printers, list_print_jobs, printer_status). print_cards vs print_picture vs reprint are naturally separable by content type and source. No overlap or confusion.

Naming Consistency4/5

Mostly follows a verb_noun snake_case pattern (print_cards, preview_cards, cancel_print, list_printers, list_print_jobs). Minor deviations exist: printer_status is noun_noun rather than a verb, and reprint is a bare verb. Still predictable and readable overall.

Tool Count5/5

Eight tools is well-scoped for a thermal printer server, covering printing, previewing, job management, and device queries. Each tool earns its place with no redundancy.

Completeness4/5

Covers the core print lifecycle: print, preview, list jobs, reprint, cancel, plus printer listing and status. Minor gaps like clearing job history or deleting individual jobs exist but are not essential to core workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to print documents, manage print queues, and control printers on macOS/Linux systems via the CUPS printing system. Supports printing PDFs, text files, and other formats with options like duplex printing, landscape orientation, and multiple copies.
    6
    13 npm
    12
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with Memobird thermal printers to print text, HTML, web pages, and images directly from MCP-enabled clients. It includes tools for device binding, image conversion, and monitoring print job status.
    9 npm
    1
    ISC
  • A
    license
    A
    quality
    C
    maintenance
    Enables printing PNG labels to a nearby thermal label printer over local serial or Bluetooth, with tools for rendering previews, checking printer status, and printing with confirmation.
    5
    MIT