Skip to main content
Glama
keaisizhutou

PD01 Printer MCP

by keaisizhutou

PD01 Printer for macOS

让 Mac 通过蓝牙连接 PD01 热敏打印机:检查连接、排版中文、查看 PNG 预览、确认后打印。提供命令行入口,并保留原项目的 Streamable HTTP MCP 服务。

基于 1124823599331l-boop/pd01-printer-mcp 的 Mac 适配,沿用原项目的蓝牙、打印协议和排版代码,并非从零重写驱动。原作者署名与 MIT 许可证见 NOTICE.md 和 LICENSE。

把链接交给 AI 安装

把本仓库地址发给能操作你这台 Mac 终端的 AI,并告诉它:

请先阅读 README 和 INSTALL.md,按清单在我的 Mac 上安装、启动并完成不出纸验收。你能执行的命令请自己完成;需要系统授权或我操作打印机时再说明。先不要打印。

INSTALL.md 是 AI 的执行清单,包含环境检查、隔离安装、服务身份核对、真实 MCP 调用及首次选机。安装和打印连接分别验收。每个人使用自己的设备选择、校准和任务目录,仓库不附带作者的打印机配置。私有仓库需要先具备访问权限。

Related MCP server: luckjingle-mcp

安装

需要带蓝牙且已登录桌面的 Mac、Python 3.12、Apple Command Line Tools(含 Swift 编译器)、兼容原项目 0x5178 协议的 PD01,以及 58mm 热敏纸。缺少编译器时先手动运行 xcode-select --install。

M 系列应使用原生 arm64 Python。Intel 的部分依赖可能需要源码编译,额外构建前提见 INSTALL.md;不要把本机已有的工具当作所有朋友机器的默认条件。

git clone https://github.com/keaisizhutou/pd01-printer-macos.git
cd pd01-printer-macos
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --require-hashes -r requirements.lock
python -m pip check
python pd01_mac.py setup-confirmation

打开打印机、装纸,关闭占用它的手机打印 App。开启 Mac 蓝牙。首次运行如果出现蓝牙访问提示,请允许正在运行程序的终端或应用;被拒绝时到「系统设置 → 隐私与安全性 → 蓝牙」检查权限。Mac 使用程序扫描 BLE,不必照搬 Windows 的手动配对步骤。

先检查,再预览和打印

python pd01_mac.py check
python pd01_mac.py prepare --text-file ./message.txt --font-size 36 --align center

CLI 和 MCP 共用设备选择规则:首次未绑定时,只发现一台同名 PD01 才自动保存选择;发现多台时停止,不取扫描列表中的第一台。可以先查看列表并明确指定:

python pd01_mac.py printers
python pd01_mac.py select-printer <列表中的设备编号>
python pd01_mac.py check

MCP 对应使用 list_printers、select_printer(device_id)。扫描和选择均不打印;已选择的设备离线时,只报告该设备不可用,不自动换成另一台同名机器。选择保存在本机 device.json。设置了 PD01_DEVICE_ADDRESS 时它优先,选择另一个编号会明确报错,需先更新或移除该变量。

图片也可以先准备成黑白点阵预览:

python pd01_mac.py prepare-image --image-file ./drawing.png

图片按比例缩放至 384 点宽,透明区域按白底处理,再转换为与打印数据一致的黑白预览。图像任务的本机确认窗口显示「黑白图片 · 1 张」,不显示文字字号。返回任务 ID 后仍用同一个 print 命令和人工确认流程;准备图片不会出纸。

文字与图片也可以上下混排。把下面的内容保存为 UTF-8 的 layout.json,图片路径相对于该文件所在目录:

{
  "blocks": [
    {"type": "text", "text": "图文示例", "font_size": 36, "align": "center"},
    {"type": "spacer", "height": 12},
    {"type": "image", "path": "drawing.png", "width": 320, "align": "center"},
    {"type": "text", "text": "这里是图片说明。\n这里是第二行。", "font_size": 28}
  ]
}
python pd01_mac.py prepare-mixed --manifest ./layout.json

混排合成为一张 384 点宽的实际点阵预览,沿用同一个任务和确认按钮。当前支持上下排列,区块可左对齐、居中、右对齐;不支持文字围绕图片。最多 32 个区块,原图最多 1600 万像素,不接受多帧图片;单张点阵最多 4000 行,超出时明确报错,不截断内容。

message.txt 使用 UTF-8 编码。prepare 返回原文、字号、任务 ID 和本地 PNG 路径,不连接打印机、不出纸。默认字号为 36,居中排版;可用范围 12–72。长行优先在空格或较靠后的句读处换行,尽量避免中文句末标点单独落在行首、开括号落在行尾,以及拆开能放进一行的英文单词。超长英文单词仍会分开。手动换行和空白行保留。

查看 PNG 并确认原文和布局后,用返回的任务 ID 执行。这会打开 Mac 本机确认窗口:

python pd01_mac.py print <任务ID> --confirm CONFIRM_PRINT

窗口显示本次保存的实际图片、字号、对齐方式、1 张的份数,以及绑定的打印机名称和编号末尾。目标在打开窗口前固定;等待确认或排队期间修改默认设备,不会改变这张任务的目标。只有点击「确认打印 1 张」才会发送到打印机。 取消、关闭窗口、等待 120 秒、编译失败或没有可用桌面时均不发送。取消后如需重新打印,重新准备一个任务;同一任务不会再次弹窗。首次构建窗口可能较慢,建议先运行上面的 setup-confirmation,后续使用本机缓存。

可单独测试窗口,按钮点击后也不连接打印机、不出纸:

python pd01_mac.py confirm-demo

MCP 和命令行共用持久化任务记录;同一任务跨入口、跨进程只允许尝试一次。发送前先以独占方式创建并刷新尝试记录,失败、取消或程序重启后仍保留。发送异常、超时或结果不明确时,不自动重打;先看实物。确实需要另一张时,重新 prepare 生成新任务,并重新确认。内容相同的新任务仍是独立任务;这不是按文本去重。

打印返回 data_sent 只说明蓝牙数据发送完成,不能证明纸张完整输出。check 验证蓝牙连接和写入通道;status 查询设备状态。纸张、纸仓等状态只按本机对照验证过的规则解释,未验证的能力显示未知,不套用其他机型的故障位。

在支持通知的 BLE 连接上,发送前订阅 AE02 并等待有效状态回包;收不到回复就停止,不发送图片。打印数据分包间隔为 20 毫秒,发送结束后保持连接两秒,再查询一次状态,避免立刻断开。发送后无回包会报告结果不确定并阻止自动重试。device_reply_after_send 表示收到了设备回复,device_ready_reported 表示收到设备就绪/恢复接收的 AE 通知;二者都不能代替用户确认实物出纸。

排队与超时

人工确认窗口等待期间不占用蓝牙队列。点击确认后,任务先进入「等待打印机」阶段,轮到后再连接并检查状态。不同数据目录仍共用用户目录 Library/Application Support/pd01-printer-macos/hardware.lock;锁文件保留,文件存在不代表设备忙,进程退出后系统会释放锁。排队按锁可用性调度,不保证严格先进先出;其他电脑、手机 App 和旧版本程序不在该队列内。

阶段

上限

等待蓝牙队列

120 秒

单次扫描

12 秒

建立连接

20 秒

启用状态通知

5 秒

每次蓝牙写入

5 秒

每次等待 A3 状态回复

3 秒

停止通知、断开连接

每步 3 秒

状态查询整体,不含排队及清理

90 秒

打印操作整体,不含按钮确认、排队及清理

120 秒

超时会返回发生阶段。发送前超时明确标为未发送;发送已开始后超时标为结果不确定,不自动续传或重打。停止通知失败时仍会尝试断开;清理失败会报告,原有故障不会被清理错误覆盖。应用时限覆盖异步蓝牙等待,仍依赖系统及底层库响应取消,不能强制中断卡死的同步系统调用。

升级后重启已运行的 MCP 服务,让它加载新队列、选机工具和超时逻辑。队列超时、取消或故障后,旧任务的单次尝试记录仍保留;需要另一张时重新准备并再次点击本机按钮。

故障反馈与本机验证

python pd01_mac.py status

状态查询只发送 A3 查询指令,不打印、不走纸。连接不可用、状态超时、传输中断和发送后失联会返回错误代码、中文说明、处理建议,以及结果是否不确定。MCP 的 check_printer 也使用同一状态查询。

可反馈的情况及处理方式:

情况

反馈与处理

没发现打印机、扫描或连接失败

提示检查电源、距离、蓝牙权限和手机 App 占用;不将某个原因当作已确定事实

状态查询无有效回复、通知通道不可用

告知当前无法判断设备状态;已启用的故障检查不能执行时阻止打印

本机已验证的缺纸/纸仓故障

发送前拦截;发送期间收到异常时停止后续分包,保留异常,不因后续恢复回包而抹掉

发送中断、发送后无状态回复

提示可能已经部分出纸,不能自动重打

图片不存在、损坏、多帧、过大、混排格式错误或超长

在准备预览时说明具体问题,不连接打印机

确认取消、关闭、超时、构建或窗口失败

区分取消与失败,均不发送

任务不存在、预览被改动、同一任务重复执行

阻止发送;重复任务需先检查上次结果

本机磁盘满、权限不足或目录只读

提示处理本机存储;发送已开始时保留结果不确定的语义

已配置的本机校准记录损坏或与设备不匹配

阻止打印,提示检查或重新校准,不悄悄跳过检查

运行 python pd01_mac.py job-status <任务ID> 或 MCP get_job_status 可以查看本机最近记录的任务阶段和错误建议,包括待确认、设备检查、发送、等待回包、已发送、取消、被拦截及结果不确定。它读取持久化记录,不代表正在实时监视设备;程序被强制关闭后,最后一个阶段仍会保留。physical_output_verified 始终为 false,软件不能据此声称已实际出纸。

走纸但空白

用户反馈「出了白纸」「走纸了但没有字或图」时,AI 可调用 report_blank_output(job_id);命令行也可以记录该情况并获取排查提示:

python pd01_mac.py report-blank <任务ID>
python pd01_mac.py job-status <任务ID>

提示依次检查热敏面朝向、纸是否压好与纸仓盖是否扣紧、是否使用适配的热敏纸;仍有问题时建议按设备说明做自检对照。程序同时检查该任务保存的预览是否包含黑色内容,预览本身为空时先提示重新准备内容。热敏纸辨认与装纸的一般排查依据见 Star Micronics 支持说明,具体装纸方向以 PD01 本机说明为准。

这是客户端转述症状后生成的排查建议,不是自动检测到纸放反;返回 sensor_confirmed: false。反馈保存在对应任务的本机记录,之后查询任务状态可读到。未发送、已取消或发送前被拦截的任务不能记录成出白纸。这个入口不会连接打印机、出纸、改变原发送结果或解除单次尝试限制;调整后需另建任务并重新点击本机按钮。

只在设备暴露可读的标准 Battery Level 特征、且返回值有效时显示电量百分比。接口不存在、读取失败或数据异常时返回未知,不显示成 0%。本机 PD01 实际连接查询未发现该标准特征,因此当前无法读取电量;其他私有接口尚未验证。未定义未经验证的低电量阈值,也不将 A3 后面的未知字节解释为电量或温度。标准定义见 Bluetooth Battery Service。

纸仓和缺纸的对照步骤如下,每步需由操作者先完成实物操作,再运行对应命令:

# 有纸、压好并扣紧纸仓
python pd01_mac.py status --samples 3 --sample-label normal
# 打开纸仓盖,纸留在里面
python pd01_mac.py status --samples 3 --sample-label cover_open
# 取出纸卷,重新扣紧空纸仓
python pd01_mac.py status --samples 3 --sample-label paper_missing
# 装回纸、压好并重新扣紧纸仓
python pd01_mac.py status --samples 3 --sample-label recovered
python pd01_mac.py calibrate-status

四组数据必须来自同一台设备。只从有协议依据的首个状态字节提取可重复变化的标志;不把后面可能变化的读数猜成故障。恢复状态必须回到正常基准,否则拒绝启用规则。开盖与缺纸若无法区分,只提示「缺纸或纸仓未扣好」;未观察到稳定差异的情况保持未验证。

规则保存在本机 status-profile.json,绑定当前设备,不随代码上传或自动迁移到其他打印机。规则启用后,发送前检测到已验证故障会阻止打印数据,发送期间检测到故障会停止后续分包并提示结果不确定;程序不会自动重打。错误及处理建议保存在该任务本机记录中。

检测到传感器标志不代表能判断纸是否实际压紧、纸面朝向、是否完整走纸或图案是否完整。未获得相应硬件证据前,这些项目仍不能自动确认。

本地数据

设备标识、原文、预览和打印尝试记录默认保存在用户目录的 Library/Application Support/pd01-printer-macos/,不在仓库里。MCP 和命令行都可设置环境变量 PD01_STATE_DIR;命令行也可通过全局参数 --state-dir 指定其他私有目录。跨入口使用同一任务时必须使用相同的数据目录。不要将这些数据、真实设备地址或凭证提交到 GitHub。

Mac 蓝牙使用系统分配的设备 UUID;自检纸上的蓝牙 MAC 地址不能直接照填为 Mac 的设备 ID。存在多台同名设备时,CLI 和 MCP 均拒绝随意选择;使用扫描列表中的编号明确选择目标。

MCP 入口

python printer_server.py

本地地址为 http://127.0.0.1:4176/mcp,传输方式为 Streamable HTTP。可用工具:

  • list_printers:扫描同名设备并返回本机编号,不连接或打印。

  • select_printer:从扫描列表明确选择设备,用于之后的新任务,不打印。

  • check_printer:查询设备状态并返回本机已验证的故障提示,不出纸。

  • prepare_text:准备文字,默认 36 号字、居中,返回结构化参数和实际 PNG 图片,不出纸。

  • prepare_image:传入本机图片路径 image_file,准备黑白图片并返回实际 PNG 预览,不出纸。

  • prepare_mixed:传入上述 blocks 及图片相对路径的 base_dir,准备图文混排与实际 PNG 预览,不出纸。

  • get_job_status:读取任务最近记录的阶段、错误原因和处理建议,不连接打印机。

  • report_blank_output:仅在用户反馈走纸但空白时调用,记录客户端反馈并返回装纸、热敏面及预览检查建议;不连接设备,不重打。

  • print_prepared:传入任务 ID 和 CONFIRM_PRINT 后打开本机确认窗口,点击「确认打印 1 张」才尝试发送。

  • disconnect_printer:断开连接。

安装验收还可读取 http://127.0.0.1:4176/health。它只返回运行进程的服务、源码、数据目录、代码和 Python 环境指纹,用于识别端口上的服务是否属于本次安装;不返回原始路径、设备编号或打印内容,也不检查打印机。核对方式见 INSTALL,不能用 HTTP 正常代替实际 MCP 调用与实物验收。

Mac 字体自动尝试系统黑体等中文字体;也可设置 PD01_FONT_PATH 为现有 TTF/TTC 字体路径。服务默认只监听本机;远程访问必须另外配置身份验证和安全网络入口。

AI 客户端应展示返回的图片和完整原文,再向用户取得明确批准。图片内容与保存的打印任务一致;发送前会校验图片摘要。prepare_text 的结构化结果仍含任务 ID、原文、字号、对齐和图片尺寸;图片作为额外的 MCP 内容块返回,能否直接显示取决于客户端。

本机确认: CONFIRM_PRINT 只用于请求打开确认窗口,不能代替窗口中的按钮。MCP 和 CLI 的发送路径均强制等待本机窗口批准;没有跳过确认的 CLI 参数、环境变量或 HTTP 批准接口。窗口通过私有子进程管道返回与本次任务、图片摘要和随机值绑定的决定;不会保存可复用的批准令牌。窗口按钮等待上限仍为 120 秒;单次 MCP 工具调用还可能包含排队、扫描和传输,建议客户端允许 600 秒,首次使用前先完成窗口构建。

该保护用于防止普通 MCP 调用直接出纸,并不是对抗本机同权限恶意程序的操作系统安全隔离:能修改源码、替换程序或自动操作桌面的程序仍可能绕过。确认机制也不代替网络身份验证。每个任务有点阵长度上限,但不累计限制不同任务的总用纸量,也不按内容合并不同任务。

打印接口统一返回 data_sent 与 physical_output_verified: false,不再使用 printed: true 表示实物成功。扫描、选择、状态查询、发送和断开共用跨进程蓝牙队列;同一 Mac 用户运行的 CLI 和 MCP 会串行使用蓝牙,即便它们使用不同的本机数据目录。

验证范围

2026-10-28 已在一台 Mac 和一台 PD01 上完成 BLE 连接,以及使用本仓库所沿用的协议发送 24、40、36 号中文排版。用户反馈促成了字号调整。后续共用任务存储、MCP 图片返回及换行改进通过无硬件测试和本机中文预览检查。本机确认功能通过 Swift 编译及无硬件测试,覆盖待确认期间不发送、取消、超时、窗口失败和错误批准信息;测试窗口使用 confirm-demo,不为测试额外出纸。该结果不代表所有 PD01 固件或所有 Mac 均兼容。

2026-10-29,用户在纸张重新压好后确认文字与黑白图片均已实际出纸,本机按钮确认到打印的流程已验证。此前未出纸由用户确认与纸张未压住有关;分包延时和回包监听是独立的稳定性、可观察性改进,没有证据表明它们解决了该机械问题。

同日完成一台 PD01 的正常装纸、开盖留纸、无纸关盖、恢复装纸四组只读查询,每组至少三次。开盖与缺纸共用异常标志,恢复后回到正常基准;因此本机规则只能合并反馈「缺纸或纸仓未扣好」。该规则已在此设备本机启用,代码不会把它当作所有 PD01 的通用规则。四组回包通过同一故障判定函数回放验证,异常会在打印数据发送前被拦截;没有为验证额外打印。纸张是否实际压紧、卡纸、低电量、过热及实际走纸仍未完成设备验证。

扩展反馈、混排与验证边界见 VALIDATION.md。混排经过本机预览、无硬件流程及实物出纸验证,用户在调整纸卷方向后确认文字与小猫图片清楚完整。前后两张点阵相同,显色异常及正常打印时设备均未报告已验证故障,现有状态回包不能据此识别纸面方向或显色质量。软件不会为了测试故意造成卡纸、过热或过放电。

python -m unittest discover -s tests -v

项目不附带个人设备标识、打印内容、预览图片、日志或访问凭证。

维护与依赖更新

requirements.txt 是三个直接依赖的维护输入,requirements.lock 锁定完整依赖及分发包哈希。普通安装使用后者。修改依赖后,维护者可以用 uv 重新解析,并更新输入摘要:

uv pip compile requirements.txt --python-version 3.12 --universal --generate-hashes --no-annotate --no-header -o requirements.lock
python3.12 - <<'PY'
import hashlib
from pathlib import Path
path = Path('requirements.lock')
body = '\n'.join(line for line in path.read_text().splitlines() if not line.startswith('# source-sha256:'))
digest = hashlib.sha256(Path('requirements.txt').read_bytes()).hexdigest()
path.write_text('# source-sha256: ' + digest + '\n' + body + '\n')
PY

依赖升级需重新在空虚拟环境安装、执行 pip check、构建确认窗口并运行全部测试。GitHub Actions 使用 Mac 环境执行相同流程;测试禁止真实蓝牙和真实打印,不能代替其他 Mac、固件及实物的兼容性验证。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables printing structured documents to ESC/POS thermal printers via a CUPS queue, with tools for printer info, print jobs, and template management.
    1
    -
  • 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
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables printing text, QR codes, and images directly to NIIMBOT B1 BLE label printers without vendor apps or cloud, with orientation control, fit validation, and local preview tools.
    -