Single tool `print(markdown, title?, timestamp?, qr_urls?, cut?)`. Hand-rolled line-by-line markdown parser translates headings/bold/code/lists/blockquotes/ HR/links to ESC/POS, then sends raw bytes via TCP to 192.168.0.184:9100. Mirrors mcp-gemma4 layout (stdio server, single server.py, mcp package).
mcp-pos-print
MCP server that prints markdown to the Epson TM-m30 receipt printer at 192.168.0.184:9100. Mirrors the mcp-gemma4 layout.
See ~/bin/POS_PRINT.md for the printer reference (Font B columns, native QR, troubleshooting) and DECISIONS.md for design rationale.
Tool
print(markdown, title?, timestamp?, qr_urls?, cut?)
markdown(required) — body to print. Supports# / ## / ###headings,**bold**and`code`inline, fenced```code blocks (no wrap),---/***horizontal rules,-/*/1.lists,> blockquotes,[text](url)links, blank lines. Long lines word-wrap at 57 cols.title— bold centered header above the body.timestamp— bool, defaulttrue. PrintsMon, May 25 14:32 ETunder title.qr_urls— list of URLs printed as native hardware QR codes at the end.cut— bool, defaulttrue. Auto-cut paper.
Returns Printed N bytes to 192.168.0.184:9100. on success, or a clear error string if the printer is unreachable.
Install
cd ~/bin/mcp-pos-print
python3 -m venv .venv
.venv/bin/pip install -e .
Register in ~/.claude.json (global scope):
{
"mcpServers": {
"pos-print": {
"command": "/home/claude/bin/mcp-pos-print/.venv/bin/python",
"args": ["/home/claude/bin/mcp-pos-print/server.py"]
}
}
}
Restart Claude Code or run /mcp to reconnect.
Test
.venv/bin/python test_server.py
Prints a self-test page covering headings, inline formatting, lists, code blocks, blockquotes, horizontal rules, and a QR code. Requires the printer reachable at 192.168.0.184:9100.
Config
POS_PRINTER_IP— default192.168.0.184POS_PRINTER_PORT— default9100POS_PRINTER_TIMEOUT— TCP timeout in seconds, default10
Markdown subset
Hand-rolled line-by-line parser, no markdown-it-py dependency. Supported:
| Markdown | Output |
|---|---|
# Heading |
bold + 2x size, centered |
## Heading / ### Heading |
bold, left |
**bold** inline |
bold run |
`code` inline |
passed through (already monospace) |
```fenced``` |
preserved verbatim, no wrap; » marks chars truncated past col 57 |
--- / *** / ___ |
thin separator across full width |
- item / * item |
* item, hanging-indented continuation |
1. item |
1. item, hanging-indented continuation |
> quote |
| prefix |
[text](url) |
text (url) |
| blank line | blank line |
| anything else | word-wrapped at 57 cols |
Not supported (by design): images, tables, nested lists, footnotes, HTML. Use qr_urls for QR codes — there's no QR markdown syntax.
Troubleshooting
cannot reach printer— power, network, paper, or ARP issue.ping 192.168.0.184first.timed out— same. The TM-m30's WiFi sometimes drops ARP entries; a ping usually re-resolves.- Garbled output — most likely you mixed an external script that uses Font A; this server hard-codes Font B (57 cols). If you're seeing it from
print, file a bug. - No paper feed at end — make sure
cutisn't explicitlyfalse.