puffco-mcp
v0.4.0
Published
MCP server to control a Puffco New Proxy / Peak Pro over Bluetooth LE (LORAX protocol)
Maintainers
Readme
An MCP server to control Puffco Devices over Bluetooth LE.
Exposes the device as MCP tools (connect, status, preheat, boost, profiles, temperature, stealth, lantern, colors, brightness) so any MCP client can drive your Puffco.
Protocol credit: Fr0st3h/Puffco-Reverse-Engineering-Writeup. Reverse-engineered for personal interoperability. Not affiliated with Puffco.
Requirements
- Node.js 20+
- A machine with Bluetooth LE, within ~10m of the device
- The Puffco in Bluetooth/pairing range (not connected to the phone app)
macOS uses CoreBluetooth via @stoprocent/noble — grant the terminal/host
Bluetooth permission on first run.
Install & run
No install needed — run straight from npm with npx:
npx puffco-mcpOr install globally:
npm install -g puffco-mcp
puffco-mcpMCP client config (npx)
{
"mcpServers": {
"puffco": {
"command": "npx",
"args": ["-y", "puffco-mcp"]
}
}
}OpenClaw
openclaw mcp add puffco --command npx --arg -y --arg puffco-mcpFrom source
npm install
npm run build
node dist/index.jsTools
| Tool | Description |
|------|-------------|
| puffco_connect | Scan, connect, run LORAX auth handshake |
| puffco_disconnect | Disconnect |
| puffco_status | Battery %, heater temp, operating state, total dabs, name |
| puffco_device_info | Model, serial, firmware revision |
| puffco_diagnostics | Full telemetry: heater power/duty/resistance/voltage/current, battery voltage/temp/capacity/current, charge/input current, magnetic field, uptime, safety thermal est, raw heater temp |
| puffco_stats | Lifetime/trip heat cycles + time, total dabs, dabs/day, approx dabs remaining, chamber type |
| puffco_profile_get | Read one or all 4 heat profiles (name, temp, time, color, boost) |
| puffco_profile_set | Set one profile field (name/temp/time/color/boostTemp/boostTime) |
| puffco_logs | Read audit + fault logs (best-effort) |
| puffco_set_brightness | Set LED brightness 0-255 (all segments) |
| puffco_preheat | Start a heat cycle |
| puffco_abort | Abort/stop the current heat cycle |
| puffco_boost | Boost active cycle |
| puffco_command | Raw device command (heatCycleStart/Abort/Boost, sleep, idle, …) |
| puffco_select_profile | Select profile 1-4 |
| puffco_set_temp | Override cycle temperature (C) |
| puffco_stealth | Toggle stealth mode |
| puffco_lantern | Lantern on/off |
| puffco_lantern_color | Lantern RGB |
| puffco_dabs_today | Dabs today (cloud) + avg duration & popular temp |
| puffco_dab_history | Dab history by period (d/w/m/y/all) — cloud account API |
| puffco_last_dab | Timestamp of the most recent dab (cloud) |
Cloud metrics (dab history)
The BLE/LORAX interface exposes only lifetime odometer counters — the device
has no real-time clock and no per-dab timestamps. The Puffco app's Metrics
tab (dabs today/week/month, average duration, popular temp) comes from the
account cloud API (api.puffco.app). The puffco_dabs_today /
puffco_dab_history / puffco_last_dab tools mirror that API so you get
app-accurate, date-ranged numbers.
These tools authenticate as your own Puffco account — no credentials are bundled with the package. Provide tokens one of two ways:
- Env var (simplest): set
PUFFCO_REFRESH_TOKENto your account's refresh token (from the app/weblocalStorage.refreshToken). The server auto-refreshes the short-lived access token from it and persists the rotated pair. - Extract helper: run a Chrome with remote debugging on a logged-in
puffco.app tab, then:
This writesnode scripts/extract-tokens.mjs --port 9222~/.config/puffco-mcp/tokens.json(override withPUFFCO_TOKEN_FILE).
Optional env: PUFFCO_SERIAL (default device for puffco_last_dab),
PUFFCO_TIMEZONE (default America/New_York).
⚠️ This calls a private, undocumented Puffco endpoint with your personal account auth. It's for your own use — don't share or publish your tokens.
Full token walkthrough: see SETUP.md.
For AI agents
If you're an MCP/agent client, see SKILL.md for a task-oriented
guide: when to use BLE vs cloud tools, the connect-first rule, the heating
safety rule, and how to answer "how many dabs today?". SKILL.md is
OpenClaw-skill compatible (frontmatter + MCP install metadata).
How it works
The New Proxy does not use the Peak Pro one-characteristic-per-field GATT.
It speaks the LORAX protocol — a path-based command/reply system over
service e276967f-…:
60133d5c(write) — command channel;8dc5ec05/43312cd1(notify) — replies/events- Frame:
seqId(u16le) + opcode(u8) + payload; replies matched byseqId - Opcodes: getAccessSeed(0), unlock(1), getLimits(2), readShort(16), writeShort(17), write(34)
- Values addressed by path, e.g.
/p/bat/soc,/p/app/mc,/p/app/stat/id - Auth: getAccessSeed →
SHA256(HANDSHAKE2 ‖ seed)[:16]→ unlock - Battery SOC is a u16 fixed-point hundredths (9471 = 94.71%)
The legacy Peak Pro f9a98c15-… layout (Firmware X E0 handshake) is also
mapped in src/protocol.ts.
Protocol credit: meekzyr/PuffcoPC and Fr0st3h.
Status
v0.4 — New Proxy (LORAX) device control + telemetry (live-verified reads, auth, and write/heat path), full per-profile editing, and cloud dab-history tools (dabs today/week/month, app-accurate). Audit-log readout is best-effort. PRs welcome.
License
MIT
