Skip to main content
Glama

luckjingle-mcp

An MCP server that lets Claude (or any MCP client) design and print things to cheap Bluetooth thermal label/sticker printers, and manage more than one of them - print to whichever one you select, or name one explicitly per job.

Printer support is pluggable: each printer family is a small driver (see "Adding support for a new printer" below). Right now there's one driver, luckprinter, covering "LuckPrinter SDK" printers - the ones sold under names like NHOWIN, NDYIN, C&Co 3128, DP-L1S, etc, that all run on the "LuckPrinter SDK" behind the "Luck Jingle" phone app (159+ rebrand models share this SDK).

These printers don't publish an official protocol or SDK. luckprinter talks to them using a protocol reverse engineered by the community by decompiling the Android app (see NOTICE.md for credits/ sources): a standard ESC/POS GS v 0 raster image command plus a handful of vendor-specific control commands. If your printer's BLE service exposes characteristics ff01/ff02 under service ff00 (check with probe_device, see below) it's likely compatible as-is - but see the "Adding support for a new printer" section if a test print doesn't work, since more than one incompatible protocol shares that same GATT layout.

Other servers in this repo

This repo also has netprint-mcp - a separate, much simpler MCP server for printing documents (PDFs, images, etc) to a regular network printer already set up on this machine, via CUPS. No BLE, no daemon - see its own README for setup.

Related MCP server: Memobird MCP Server

Architecture

This is split into two processes, which is unfortunately necessary on macOS:

  • luckjingle-daemon - owns the actual Bluetooth connection. Must run as its own independent app (see "macOS Bluetooth permission" below), not as a subprocess of Claude.

  • luckjingle-mcp - the MCP server Claude talks to. It's a thin client that forwards tool calls to the daemon over http://127.0.0.1:8765.

Requirements

  • Python 3.10+

  • macOS, Linux, or Windows with Bluetooth LE support (uses bleak)

Install

cd /path/to/iocane   # wherever you cloned this repo
python3 -m venv .venv
.venv/bin/pip install -e .

macOS Bluetooth permission (important)

On macOS, any process descending from an app that hasn't declared Bluetooth usage in its Info.plist will hard-crash (not prompt) the instant it touches CoreBluetooth. Since this MCP server runs as a subprocess of whatever launched Claude, that includes it. macos_app/LuckJingleDaemon.app works around this: it's a minimal app bundle that declares NSBluetoothAlwaysUsageDescription, so macOS can show a normal permission prompt for it instead.

You must start the daemon by opening this app directly - not from inside Claude/a terminal spawned by Claude:

open /path/to/iocane/macos_app/LuckJingleDaemon.app

(The bundle's launcher script locates its own venv relative to itself, so this works from whatever path you cloned the repo to. If the daemon doesn't start and nothing obvious shows up, check ~/Library/Logs/luckjingle-daemon.log.)

The first time, macOS will show a Bluetooth permission prompt attributed to python3.14 (or similar) - accept it. It's a background app (no dock icon, no window) that just listens on 127.0.0.1:8765; leave it running whenever you want to print. If you want it running automatically, add it to System Settings → General → Login Items.

Known glitch: the permission dialog can sometimes get visually stuck (looks like clicking "Allow" does nothing). If that happens, check whether it actually took effect before assuming otherwise - macOS's own dialog rendering can lag behind the real permission state; killing and reopening the daemon app is usually enough to get a clean prompt.

On Linux/Windows this split isn't necessary, but the daemon/client architecture works the same way regardless - just run luckjingle-daemon however you'd normally run a background service.

Find and verify your printer

  1. Power on the printer and make sure your phone isn't already connected to it via its own app (force-quit the app, or turn the phone's Bluetooth off temporarily) - a printer already connected elsewhere won't advertise for a new connection.

  2. Ask Claude to run scan_printers (or start the daemon and curl -X POST http://127.0.0.1:8765/scan -d '{"timeout": 10}'). Results are sorted by signal strength - your printer is usually the strongest signal since it's right next to you, but cheap BLE modules often advertise a generic factory name (ours showed up as PPS1_6306_BLE, not any recognizable brand name) rather than the retail brand printed on the box.

  3. Before trusting a name-based guess, confirm it with probe_device (address) - a compatible printer's GATT services should include:

    service 0000ff00-... with characteristics:
      0000ff01-...  (notify)
      0000ff02-...  (write)

    This UUID pattern is a common generic BLE-serial scheme also used by unrelated devices, so a name match alone isn't proof - but the service layout combined with a signal-strength match is a strong signal.

  4. Save it: ask Claude to run add_printer("<name>", "<address>") - e.g. add_printer("kitchen", "AA:BB:CC:DD:EE:FF") - or curl -X POST http://127.0.0.1:8765/add_printer -d '{"name": "kitchen", "address": "..."}'. The first printer you add becomes the active one automatically. (If you only ever have one printer, set_printer_address(address) is a shorter equivalent that skips naming it.)

Printer profiles are saved to ~/.config/luckjingle-mcp/config.json and reused for future print jobs, so you only need to do this once per printer.

Managing multiple printers

  • list_printers() - see every configured printer and which one is active.

  • select_printer("<name>") - switch which printer print_text/ print_image use by default.

  • print_text(..., printer="<name>") / print_image(..., printer="<name>")

    • print to a specific printer for one job, without switching the active one.

  • set_printer_options(..., name="<name>") - tune width/density/font for a specific printer instead of the active one.

  • remove_printer("<name>") - drop a configured printer. If it was active, another remaining one (if any) becomes active.

Register the MCP server with Claude Code

claude mcp add luckjingle -- /path/to/iocane/.venv/bin/luckjingle-mcp

Or add directly to your MCP config (e.g. ~/.claude.json or .mcp.json):

{
  "mcpServers": {
    "luckjingle": {
      "command": "/path/to/iocane/.venv/bin/luckjingle-mcp"
    }
  }
}

This just needs to be done once; the daemon app still needs to be started separately each time you want to print (see above).

Tools

  • scan_printers(timeout=6.0) - list nearby BLE devices (name, address, signal strength)

  • probe_device(address, timeout=15) - connect and list GATT services/characteristics, to verify a candidate device before adding it

  • add_printer(name, address, driver="luckprinter") - add or update a named printer profile; the first one added becomes active

  • list_printers() - list every configured printer and which is active

  • select_printer(name) - switch the active printer

  • remove_printer(name) - remove a configured printer

  • set_printer_address(address) - shortcut for the single-printer case: updates the active printer's address (creating one named "default" if none exists yet)

  • get_printer_config() - show the active printer's saved settings

  • set_printer_options(width, density, font_path, name=None) - tune print quality: width in dots (384 is standard), density 0-2 (light/normal/ dark, leave unset for the printer's own default); name targets a specific printer instead of the active one

  • print_text(text, font_size=24, align="left", printer=None) - print wrapped text; printer targets a specific printer for this job only

  • print_image(image_path, dither=True, printer=None) - print an image file, resized to the paper width and converted to black & white; printer targets a specific printer for this job only

  • print_label(text, font_size=24, align="center", border=None, dither=None, save_as=None, printer=None)

    • compose and print a text label, optionally framed by a saved border (e.g. "Flux Capacitor" with the "dancing kittens" border); dither overrides the automatic choice (dithered only when a border is present); pass save_as to also save it for reprinting later

  • save_label(name, text, font_size=24, align="center", border=None, dither=None)

    • save a label without printing it, for print_saved_label later

  • list_labels() - list every saved label

  • remove_label(name) - delete a saved label

  • print_saved_label(name, printer=None) - reprint a label saved with save_label or print_label(..., save_as=...)

  • save_border(name, image_path) - save an image as a reusable named border that print_label/save_label can frame text with

  • list_borders() - list every saved border's name

  • remove_border(name) - delete a saved border

  • get_daemon_info() - checks whether the daemon is reachable and explains how to start it if not

To print a custom design (a label with a logo, a QR code, a styled layout, etc), have Claude generate a PNG with whatever tool/script fits, save it to disk, then call print_image with that path.

Saved labels and borders

  • Labels are a saved (text, font size, alignment, border) combo you can reprint by name later without repeating everything - either save one up front with save_label, or print now and save in the same call with print_label(..., save_as="...").

  • Borders are a saved image (e.g. a strip of clipart) that frames a label's text. Save one with save_border("dancing kittens", "/path/to/ kittens.png"), then reference it by name: print_label("Flux Capacitor", border="dancing kittens"). The text always sits on a plain white panel in the middle so it stays legible regardless of the border's own colors - the border image itself is tiled to frame that panel, so a short repeating strip works better than one large single graphic.

Saved labels and border images live alongside the printer config, in ~/.config/luckjingle-mcp/ - config.json for the label/border metadata, borders/ for the saved border image files themselves.

Troubleshooting

  • Any MCP tool call fails with a connection error: the daemon app isn't running - see "macOS Bluetooth permission" above.

  • Connects (printer's LED changes) but nothing physically prints: the printer probably isn't in the luckprinter (LuckPrinter SDK) family this driver targets, or uses a variant that builds the image command differently. Run probe_device to confirm the GATT layout matches, and check PROTOCOL.md in thermal-pocket-printer-basic for the full command reference if you need to adapt luckjingle_mcp/drivers/luckprinter.py, or write a new driver (see below).

  • Printer turns itself off unexpectedly: this happened during development and turned out to be a bug in an earlier version of this driver (an "disable auto-shutdown" command that actually set the auto-shutdown timer to 0). If you see it again, check nothing is sending 10 FF 12 00 00.

  • Prints too light/dark: set density (0-2) via set_printer_options.

Adding support for a new printer

Support for a printer family is a small "driver" object, not a fork of this project. If probe_device shows a GATT layout this repo doesn't already handle, or a compatible-looking printer just doesn't print correctly with the luckprinter driver (see NOTICE.md - more than one incompatible protocol shares that same ff01/ff02 layout, so a matching GATT layout alone doesn't guarantee compatibility), here's how to add one:

  1. Reverse-engineer the protocol. These printers don't publish an SDK, so this means decompiling the vendor's Android/iOS app (e.g. with JADX) and finding the BLE write calls, the same way NOTICE.md's sources did for luckprinter. You're looking for: the GATT write/notify characteristic UUIDs, how the printer is woken/enabled, how a print darkness/density setting is sent (if supported), how a raster image command is framed, and how a job is fed/ended.

  2. Implement PrinterDriver. Read luckjingle_mcp/drivers/base.py for the interface, and luckjingle_mcp/drivers/luckprinter.py for a complete worked example - it's under 40 lines. You only supply command bytes and GATT characteristics; image resizing, dithering, bitmap packing, chunked writes, and text rendering are all shared and already handled by PrinterSession.

  3. Register it by adding your driver class to the DRIVERS dict in luckjingle_mcp/drivers/__init__.py, keyed by the name people will pass to add_printer(..., driver="...").

  4. Add protocol tests. See tests/test_printer_protocol.py - these use a fake transport that just records what was written, so you can pin down your driver's exact command bytes without needing the hardware present for every test run (you'll obviously still want to confirm against real hardware before calling it done).

  5. Open a PR. Mention what hardware you tested against - a driver that's only ever run against the one printer its author owns is worth having, but should say so.

Development

.venv/bin/pip install -e ".[test]"
.venv/bin/pytest -v

Tests don't need real printer hardware - they use fake transports that record what would have been sent over BLE/serial, so they run the same on a laptop with no printer nearby.

Available Tools

12 tools
add_printerA

Add (or update, if the name already exists) a named printer profile. If this is the first printer configured, it becomes the active one automatically - otherwise use select_printer to switch to it.

driver identifies the printer's protocol family - "luckprinter" (the default) covers the LuckPrinter-SDK rebrand family (NHOWIN, PPS1, C&Co 3128, DP-L1S, etc) and is the only driver available so far.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
driverNoluckprinter
addressYes

TDQS

A3.5/5.0
Behavior3/5

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

No annotations are present, so the description carries the transparency burden. It discloses the upsert side effect, the automatic first-printer activation, and that luckprinter is currently the only driver. It does not address permissions, failure modes, return values, or whether updating an existing profile resets its other settings.

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?

The description is compact and front-loaded: the core upsert behavior comes first, the active-printer rule second, and only the necessary driver detail last. Every sentence earns its place with no redundancy.

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 3-parameter configuration tool with no output schema and no annotations, the description covers the main behavior and the optional driver parameter well. It omits the address format and does not clarify the boundary with set_printer_address, so an agent lacks some situational and invocation detail.

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?

The description adds strong semantics for the driver parameter, including its default value, protocol family, and rebrand examples, and it implies name is the identity key via 'if the name already exists'. The required address parameter, however, gets no format or example, so parameter coverage remains partial.

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 clearly states the operation ('Add (or update...)') and resource ('named printer profile'), so an agent knows what the tool does. It explicitly contrasts with select_printer for switching active printers, but it does not clarify the overlap with set_printer_address, which also modifies an existing printer's address.

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?

The description provides useful context: the first configured printer becomes active automatically, and select_printer is the tool for switching afterward. However, it does not state when to use add_printer versus set_printer_address or set_printer_options, especially since the upsert behavior overlaps with those more targeted sibling tools.

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

get_daemon_infoA

Explain how to start the required LuckJingle print daemon, and whether it is currently reachable.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

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 disclosure burden. It correctly characterizes the operation as informational and includes a reachability check, but it does not explain whether the check performs network I/O, how long it may take, or how unreachable states are represented. No annotation contradiction exists.

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?

The description is a single sentence with no filler. It front-loads the main action and covers both key concerns in a compact, scannable way.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter status tool with an output schema, the description sufficiently conveys purpose and expected content. It names the daemon and the two dimensions of the returned information, and does not need to describe return values because the output schema already exists.

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 has zero parameters and no required arguments, so there are no parameter details for the description to clarify. The mention of daemon startup and reachability usefully previews what the result will cover, which is enough 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?

The description clearly identifies the resource (LuckJingle print daemon) and the two things the tool does: explain how to start it and report whether it is reachable. This distinguishes it from sibling printer configuration and printing tools. Minor ambiguity remains in 'explain how to start,' which suggests a human-readable narrative rather than a structured daemon-info response.

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?

There is no explicit guidance about when to call this tool versus alternatives, no prerequisites, and no exclusions. The phrase 'required LuckJingle print daemon' weakly implies setup or troubleshooting context, but an agent is not directly told when this tool is the right choice.

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

get_printer_configA

Return the active printer's saved configuration (address, driver, paper width, etc). Use list_printers to see every configured printer.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior3/5

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

With no annotations provided, the description carries the full burden, and it does convey the read-only nature ('Return') and that it reads 'saved' configuration rather than live device state — a useful distinction from probe_device. However, it does not disclose error behavior when no active printer exists, which is a plausible runtime scenario an agent should anticipate.

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 sentences with no wasted words: the primary action is front-loaded, the config contents are exemplified compactly, and the sibling routing is appended efficiently. Every clause earns its place.

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 zero-parameter, no-output-schema getter, the description is nearly complete: it states what is returned, scopes it to the active printer, and points to the alternative for the full list. The only gap is the edge case of no active printer being selected, which could have been stated explicitly.

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 has zero parameters and 100% schema description coverage, so the schema leaves nothing undocumented. Per the baseline for 0-param tools, a 4 is appropriate; there is no parameter semantics gap for the description to fill.

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?

The description uses a specific verb ('Return') with a precise resource ('the active printer's saved configuration') and cites example fields (address, driver, paper width). The qualifier 'active printer's' sharply distinguishes this from siblings like list_printers, and the final sentence explicitly names the sibling for the 'every printer' case.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit when-to-use-alternative directive: 'Use list_printers to see every configured printer.' This states the condition under which a sibling should be chosen instead, leaving no inference burden on the agent.

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

list_printersA

List every configured printer (name, driver, address, settings) and which one is currently active - the one print_text/print_image use when no printer is named explicitly.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

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

With no annotations provided, the description carries the full behavioral burden. It discloses exactly what the response contains (name, driver, address, settings, active printer) and clarifies the active printer's default behavior. It does not explicitly state that listing has no side effects, but the verb 'List' strongly implies a read-only operation.

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?

The description is a single well-structured sentence that front-loads the action and scope, then efficiently lists the output fields and adds the important clarifying detail about the active printer's role. Every word earns its place, with no redundancy.

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 zero-parameter list tool with no output schema and no annotations, the description provides the essential details: what is listed, what fields are returned, and how to interpret the active printer. It could additionally contrast itself with scan_printers for discovery, but that is more of an optional enhancement than a critical gap.

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 has zero parameters and schema description coverage is 100%, so there are no parameter semantics for the description to add. The baseline of 4 applies because there is nothing missing for an agent to understand how to invoke the tool.

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?

The description uses a specific verb ('List') with a clear resource ('every configured printer') and enumerates the return fields: name, driver, address, settings, and active printer. It also distinguishes the active printer's role in print_text/print_image, making the tool's purpose unambiguous and distinct from siblings like scan_printers or get_printer_config.

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?

The description provides clear context for when to use this tool: to see all configured printers and determine which one print_text/print_image will use by default. It does not explicitly state when not to use it or name alternatives such as scan_printers, but the usage context is concrete and actionable.

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

probe_deviceA

Connect to a BLE device and list its GATT services/characteristics.

Useful for confirming a candidate address (found via scan_printers) is really a supported printer before adding it - a compatible printer should expose a custom service containing characteristics ending in ff01, ff02, and ff03. Note that this GATT layout alone doesn't tell you which driver to use - more than one incompatible protocol variant shares it - so still confirm with a real test print after adding it.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes
timeoutNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

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

With no annotations, the description takes the full burden of behavior. It discloses the operation (connect, list), the expected pattern (characteristics ending in ff01/ff02/ff03), and a limitation (shared layout across incompatible protocols). It does not cover failure modes or permissions, but the core behavioral trait—that probing is not driver identification—is clearly flagged.

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?

The main purpose is the first sentence, and the second paragraph is dense but relevant usage and caveat context. No filler; every sentence earns its place.

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?

The description covers purpose, usage context, expected output (GATT services/characteristics), and a caution about the tool's limitations. Missing details, such as timeout semantics and failure handling, are minor for this simple tool and there is no output schema demanding more.

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 schema gives only field titles—'Address' and 'Timeout'—so the description must compensate. It clarifies address as a candidate BLE address from scan_printers, which helps, but it never explains what timeout controls or what format address should take; timeout is entirely unaddressed.

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?

The description opens with a specific verb and resource: 'Connect to a BLE device and list its GATT services/characteristics.' It also clearly situates the tool in a workflow (confirming a candidate address from scan_printers before adding a printer), which differentiates it from siblings like scan_printers and add_printer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to use it: to confirm a candidate address found via scan_printers is a supported printer before adding it. It also provides an exclusion—the GATT layout alone does not determine the driver, so a test print is still needed—steering agents away from over-reliance. This is precise, alternative-aware guidance.

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

remove_printerA

Remove a configured printer. If it was the active one, another remaining configured printer (if any) becomes active.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes

TDQS

A3.9/5.0
Behavior4/5

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

No annotations are provided, so the description carries the transparency burden. It discloses a non-obvious side effect: if the active printer is removed, another configured printer becomes active. This is meaningful behavioral context for a destructive operation, though irreversibility and failure cases are not covered.

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?

The description is two short sentences with the main action front-loaded and the conditional consequence placed second. Every clause earns its place, and there is no filler or redundant wording.

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 one-parameter mutation tool with no output schema, this description gives enough context to form an accurate mental model: the target resource, the operation, and the active-printer fallback. It omits edge cases like missing printer names or permanence, but those are minor for this low-complexity tool.

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%, and the description never explicitly mentions the required `name` parameter. The phrase 'a configured printer' weakly implies that `name` identifies which printer to remove, but the description does not compensate for the bare schema by clarifying the parameter's meaning or expected value.

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?

The description opens with a specific verb and resource: 'Remove a configured printer.' This cleanly distinguishes the tool from siblings like add_printer and list_printers. It further clarifies the role by stating what happens when the removed printer was the active one.

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?

The intended use is implied rather than explicit: call this when you want to remove a configured printer. The description provides useful context about the active-printer fallback, but it does not explicitly compare with alternatives or state when not to use it.

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

scan_printersA

Scan for nearby Bluetooth LE devices to find the printer's address.

Put the printer in pairing mode (usually: hold its power button, or open its companion app once) before scanning, then look for a device name that resembles the printer (e.g. containing "D1", "GB", "Q3", "Print", or a string of letters/numbers) in the results.

Requires the LuckJingle print daemon to be running (see get_daemon_info).

ParametersJSON Schema
NameRequiredDescriptionDefault
timeoutNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/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 of behavioral disclosure. It explains the prerequisite daemon, the need for pairing mode, and what to look for in results (device name patterns). It doesn't detail side effects or error behavior, but for a read-only scan the provided context is valuable and goes beyond a bare operation.

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?

The description is well-structured: purpose in the first sentence, usage guidance in the second paragraph, and prerequisite in the third. It is informative without being bloated, though the device-name-pattern list is slightly long.

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 simple optional-parameter scan tool, the description covers the main points: what it does, how to prepare, and the runtime dependency. The missing timeout semantics is the main gap, but it is a minor one given the default value and the overall simplicity.

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 only parameter, timeout, is entirely undocumented in both the schema and the description. The schema provides only title/type/default with zero description, and the tool description never mentions timeout, its unit, or its effect. Since schema coverage is effectively 0%, the description needed to compensate but did not.

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?

The description opens with a specific verb and resource: 'Scan for nearby Bluetooth LE devices to find the printer's address.' This clearly distinguishes the tool as a BLE discovery/scan operation, not a management or configuration action, and it pairs well with the related get_daemon_info pointer.

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?

It gives actionable context: put the printer in pairing mode before scanning, and requires the LuckJingle print daemon to be running (referencing get_daemon_info). It stops short of explicit 'when not to use' or alternatives, but the preconditions and steps are clear enough for an agent to decide when to call it.

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

select_printerA

Set which configured printer print_text/print_image use by default when no printer is named explicitly on the call.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes

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 burden of explaining side effects. It discloses the core mutation and the condition under which it applies, but it does not mention whether the name must already be configured, whether the selection persists, or what happens when an unknown printer name is supplied.

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?

A single front-loaded sentence with no filler. It states the action, the affected functions, and the scope condition in a compact and readable way.

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 one-parameter setter, the core invocation is clear, but with no output schema and no annotations, there is no information about return values, error behavior, or persistence. An agent can call it correctly but cannot confidently predict success confirmation or failure mode.

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 coverage is 0% and the description never formally maps the 'name' parameter to a configured printer identifier. However, phrases like 'which configured printer' and 'no printer is named' make it reasonably clear that the parameter is the printer name, though it could be more explicit about whether it expects a display name or exact configured label.

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?

The description names a concrete verb ('Set') and a specific resource (the default configured printer used by print_text/print_image). By tying the setting to calls that omit a printer name, it clearly scopes the operation and distinguishes it from sibling printer-management tools such as add_printer, remove_printer, or set_printer_options.

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 identifies when the setting takes effect ('when no printer is named explicitly on the call'), but it does not explicitly say when to choose this tool over alternatives or state prerequisites like 'the printer must already be configured.' The usage guidance is implied rather than explicit.

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

set_printer_addressA

Save the Bluetooth address of the printer for future print jobs.

This is a shortcut for the common single-printer case - it updates whichever printer is currently active (creating one named "default" if none exists yet). To configure more than one printer, use add_printer instead, which lets you name each one.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/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 disclosure burden. It reveals that this mutates the currently active printer and creates a default printer if none exists—important side effects. It could go further on permissions or reversibility, but for a simple setter this is solid.

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?

The core purpose is stated in the first sentence, followed by a brief but valuable distinction from the alternative. Every sentence earns its place; no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no annotations, this description covers the essential behaviors: what it does, what it affects, fallback creation, and when to choose a sibling instead. The presence of an output schema helps, but nothing needed for correct invocation is missing.

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 coverage is 0%, so the description must compensate. It clarifies that 'address' means the printer's Bluetooth address, adding semantic meaning the schema lacks. It does not specify format (e.g., MAC-style), but the core meaning is clear.

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?

The description uses a specific verb ('Save') and identifies the exact resource: the Bluetooth address of the printer, for future print jobs. It also explicitly distinguishes itself from the sibling add_printer by stating when each should be used.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states this is a shortcut for the common single-printer case, explains what happens when no printer exists (creates 'default'), and points to add_printer for configuring multiple printers. This gives an agent unambiguous selection criteria.

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

set_printer_optionsA

Tune print quality for a printer. width is the paper width in dots (384 is standard for common 48mm/58mm thermal labels - only change it if prints come out cropped or skewed). density (0=light, 1=normal, 2=dark) adjusts print darkness if prints look too light/dark - leave unset to use the printer's own default. font_path points to a .ttf/.otf file to use for print_text instead of the built-in fallback. name picks which configured printer to change settings for - leave unset to use the active printer.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
widthNo
densityNo
font_pathNo

TDQS

A4.1/5.0
Behavior4/5

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

With no annotations, the description takes on the behavioral burden and does more than restate the operation: it explains defaults, effects of changing width/density, and the font_path's relationship to print_text. It could additionally disclose persistence, permissions, or side effects, but the behavior described is substantially transparent.

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?

The purpose is front-loaded in one short sentence, and every following clause explains one parameter without redundancy. The conditional phrasing keeps guidance tight rather than expanding into prose.

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 four-optional-parameter setter with no required fields and no output schema, this description covers the operation, all params, and default behavior. It does not cover error cases or explicit return behavior, but those are minor for this simple configuration tool.

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

Parameters5/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 completely: each of the four parameters gets semantics, units, valid values (density 0/1/2), file-type expectations, and default behavior. This is exactly the value the schema lacks.

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 opens with a specific verb and resource ('Tune print quality for a printer') and walks through each configurable option, making the tool's purpose clear. It does not explicitly contrast itself with sibling tools like set_printer_address or get_printer_config, so it stops 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?

It gives strong parameter-level usage conditions ('only change it if prints come out cropped or skewed', 'if prints look too light/dark', 'leave unset to use the printer's own default'). However, it does not say when to prefer this tool over alternatives or when not to use it, leaving tool-selection guidance implicit.

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. Dates show when Glama detected each change.

  1. 12 tool updatesv0.1.0
    • First observedadd_printer
    • First observedget_daemon_info
    • First observedget_printer_config
    • First observedlist_printers
    • First observedprint_image
    • First observedprint_text
    • First observedprobe_device
    • First observedremove_printer
    • First observedscan_printers
    • First observedselect_printer
    • First observedset_printer_address
    • First observedset_printer_options

TDQS

A4.2/5.0
Disambiguation5/5

Each tool targets a distinct action: scanning, probing, configuring, selecting, removing, printing, and daemon status are all clearly separated. The only potentially overlapping tools (set_printer_address vs add_printer, get_printer_config vs list_printers) are explicitly differentiated in their descriptions.

Naming Consistency5/5

Every tool follows a consistent snake_case verb_noun pattern, such as remove_printer, scan_printers, add_printer, print_text, and get_daemon_info. There are no mixed naming conventions or vague generic verbs.

Tool Count5/5

12 tools is well-scoped for this server's purpose: device discovery, printer profile management, configuration, and printing are all covered without unnecessary duplication. Each tool earns its place in the workflow.

Completeness5/5

The tool surface covers the full lifecycle: scanning and probing to find a device, adding/updating/removing printers, selecting an active printer, configuring options, checking daemon status, and printing text or images. There are no obvious dead ends or missing core operations for the stated label-printer domain.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables comprehensive control and monitoring of Bambu Lab 3D printers through Claude using local MQTT, FTPS, and X.509 authentication. Users can manage print jobs, monitor real-time status, handle filament through AMS, and adjust hardware settings like temperature and lighting.
    24
    19
    19
    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.
    13
    1
    ISC
  • A
    license
    A
    quality
    F
    maintenance
    Connect AI agents to physical printers. Print receipts, shipping labels, and packing slips to your existing BizPrint-connected printers from Claude and other MCP clients.
    7
    1
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/davidray/iocane'

If you have feedback or need assistance with the MCP directory API, please join our Discord server