Printer Control Tools
All printer tools accept optional host, bambu_serial, and bambu_token arguments. If omitted, values fall back to the environment variables PRINTER_HOST, BAMBU_SERIAL, and BAMBU_TOKEN. Passing them explicitly is useful when working with more than one printer.
The server also accepts the alias variables BAMBU_PRINTER_HOST, BAMBU_PRINTER_SERIAL, and BAMBU_PRINTER_ACCESS_TOKEN, plus BAMBU_PRINTER_MODEL and BAMBU_STUDIO_PATH.
get_printer_status
Retrieve current printer state including temperatures, print progress, layer count, time remaining, and AMS slot data. Internally sends a push_all MQTT command to force a fresh status report before reading cached state.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
Chamber status decodes the current temperature from newer firmware’s packed CTC reports, including P2S, while retaining legacy chamber/frame fields.
Returns a structured object with fields including status (gcode_state string), temperatures.nozzle, temperatures.bed, temperatures.chamber, print.progress, print.currentLayer, print.totalLayers, print.timeRemaining, and ams (raw AMS data from the printer).
get_printer_filaments
Read the live AMS inventory and resolve each loaded tray to Bambu Studio
filament profile JSON paths when bambu_model is known. The result includes a
summary, per-slot display labels, profile match confidence, and a recommended
load_filaments value for simple single-material CLI slicing.
{
"bambu_model": "h2d",
"nozzle_diameter": "0.4",
"host": "192.168.1.100",
"bambu_serial": "094...",
"bambu_token": "your_access_token"
}
High-signal fields:
summary.loaded_slots, summary.resolved_profile_slots,
summary.unresolved_loaded_slots, summary.empty_slots
trays[].display_name, trays[].tray_color, trays[].remain_percent
trays[].resolved_profile_path
trays[].profile_resolution: exact-model-nozzle, model, generic, or
unresolved
trays[].match_confidence: high, medium, low, or none
recommended.load_filaments: the profile path the MCP will use for
auto-slicing when no explicit filament override is provided
list_printer_files
List files stored on the printer’s SD card. Scans the cache/, timelapse/, and logs/ directories and returns both a flat list and a directory-grouped breakdown.
This is a read-only query: it never creates directories. Optional directories absent from a successful root listing return empty lists. Authentication, TLS, permission, and transfer failures are reported as errors rather than empty or partial results.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
camera_snapshot
Capture a single JPEG frame from the printer’s chamber camera. Read-only.
Two transports are wired in, picked by bambu_model:
- TCP-on-6000 for A1, A1 mini, P1S, P1P. Native protocol per OpenBambuAPI/video.md: TLS on port 6000, 80-byte auth packet (
bblp + access token), repeating 16-byte frame header + JPEG payload. The printer first replays the last frame it buffered, which after an idle period can show the chamber as it was long ago, so the tool skips that frame and returns the next live one (about 3 s). If no live frame follows within timeout_ms, it fails instead of returning a possibly stale image.
- RTSP for X1, X1 Carbon, X1E, P2S, X2D and H2, H2S, H2D, H2C, H2D Pro. Shells out to ffmpeg with
rtsps://bblp:<token>@<host>:322/streaming/live/1 -frames:v 1. The H2 series wasn’t documented in OpenBambuAPI’s video.md but its firmware uses the same RTSP endpoint as X1 (verified live against an H2S, 2026-04-27).
Requires ffmpeg in PATH for the RTSP path. Install with brew install ffmpeg on macOS. Configure a trusted custom binary with the server-side FFMPEG_PATH environment variable, or set MCP_ALLOW_EXECUTABLE_ARG=1 before using the ffmpeg_path tool argument. The TCP-on-6000 path uses native Node TLS and does not require ffmpeg.
{
"save_path": "/tmp/snap.jpg",
"timeout_ms": 8000,
"bambu_model": "h2s",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
Returns { status, format: "image/jpeg", sizeBytes, base64, savedTo?, transport }. transport is "tcp-6000" or "rtsps-322" so callers can tell which path produced the frame. Pass save_path to also write the bytes to disk; otherwise only the base64 payload is returned.
counterpart_print_record
Use list_jobs: true to discover the retained job IDs before selecting an older job_id. Latest-job reads discover newer dispatches made by another MCP process. The process that authorized dispatch owns report writes while it is alive; after it exits, a restarted observer can take over from the saved record. Concurrent passive MCP sessions read the same disk evidence without overwriting the active recorder. Camera bytes appear once, in structuredContent, when include_frames: true.
Read the flight record of a job this server dispatched, without contacting the printer. Firmware finished means the printer finished its commands; it does not verify the physical object.
{"job_id":"optional saved record UUID", "include_frames":false}
Omit job_id for the latest job on the configured printer; ordinary printer target overrides select another saved printer. The result has contract: "counterpart/1", status: "recorded" | "unavailable", an optional version-1 record, and separate physical evidence. Bambu records allowlisted native report fields; other adapters retain their existing normalized observations, without inventing fields their firmware/adapter does not expose. A record is established at the existing send-authorization boundary, so a lost transport/helper reply still leaves the exact hash/mapping with dispatch.outcome: "unconfirmed". A successful transport reply marks it accepted; a matching active firmware report marks it observed-active. These outcomes do not verify physical success or authorize a retry. The record retains the inspected artifact SHA-256, selected plate/hash, filament mapping/materials, timestamped allowlisted state/error/stage/AMS/temperature changes, latest state, truncation count and camera metadata. Printer names, hosts, serials, credentials, arbitrary report text and URLs are excluded; the target and dispatched job identity are hashed. Raw unknown fields remain unknown; AMS remain: -1 is not empty. After an active report has been seen, firmware terminal reports freeze the job record so later cooling does not evict its failure evidence. Returned task/subtask execution IDs are hashed. A changed execution ID or an observed ended-to-active reprint invalidates current-progress evidence durably (a bounded one-byte marker), including same-filename reprints; explicit archived reads keep the original evidence. History before this feature or outside retained/connected observations is unavailable, not reconstructed by contacting the printer.
Storage is private (directory 0700, files 0600), survives MCP restart, and is capped at ten jobs, 1 MiB/2048 report changes per job, a 64 KiB visual-observation sidecar, and 32 JPEGs of at most 512 KiB each. At most four images are returned per request. Older changes/jobs are removed; droppedReports, droppedFrames and skippedCheckpoints disclose gaps. COUNTERPART_RECORD_DIR is a trusted server environment override, never a tool-selected filesystem path. Storage failure warns on stderr and marks a record volatile; diagnostics never authorize printing, resume or another mutation.
While the client monitors counterpart_print_progress, existing reports trigger bounded asynchronous preparation-frame candidates (up to three stage changes), a first-layer frame, a completed-first-layer follow-up when layer 2 is observed, then a snapshot at crossed ten-layer milestones and height fractions (5%, 30%, 60%, 90%). The 32-frame ring preserves baseline/first-layer evidence and the latest recorded empty-footprint anomaly. There is no additional status polling or autonomous watcher. Without a monitoring client, known layer geometry, a matching active job and a usable existing camera source, no physical verdict is inferred. Skipped heights are not backfilled. Each frame binds its ID, actual report layer/time, expected sliced Z, capture receipt/acquisition time and image SHA-256. Image acquisition must be at or after its associated report boundary; an active stream waits for a newer frame when its cached frame predates that boundary. Old cached frames, a layer/state change during acquisition, and bounded camera failures are marked unavailable. A stable reported layer is not a hardware-synchronized shutter. include_frames:true reads saved JPEG base64 from disk; it does not open a camera. Expected geometry is the selected 3MF plate’s or inspected standalone G-code snapshot’s sliced layer Z and extrusion-path XY bounds, including swept extrema for G2/G3 XY arcs, not a calibrated camera silhouette or measured flow. Oversize/unsupported G-code or missing layer reports leave geometry/correspondence unknown.
physical.status is unknown, consistent, suspect_no_growth or suspect_no_extrusion, independently of firmware state. Without a usable client visual observation or calibrated height measurements it remains unknown, including after FINISH. When physical.assessment is present, the client worker should fetch its frameId and any useful referenceFrameIds with counterpart_print_record using frame_format:"images" and optional frame_ids (at most four). This returns normal MCP image content exactly once, indexed by imageContentIndex in frame metadata. Image format defaults to compact view:"evidence"; omittedReports/omittedGeometryLayers disclose omitted journal detail. view:"record" retains the full forensic record. The request includes the selected sliced footprint bounds, layer/height and explicit visibility/deposition criteria.
The client vision worker then calls counterpart_print_assess with:
{"job_id":"saved job UUID","artifact_sha256":"saved dispatch hash","frame_id":"saved frame UUID","image_sha256":"saved JPEG hash","visibility":"clear","footprint_visible":true,"deposition":"absent","attempted":true}
The hashes/IDs must match the saved job and image. visibility is clear|dark|occluded|out_of_view|unknown; deposition is absent|present|unknown. Set attempted only when the frame follows attempted object deposition, and footprint_visible only when sufficient expected deposition area can be judged. Optional reference_frame_id, reference_visibility and reference_empty provide empty-bed context. A clearly visible empty footprint after attempted printing is sufficient for suspect_no_extrusion; no reference is required. A lowered, dark or occluded reference is not proof and does not suppress a clear direct observation. Dark/occluded/unlocatable current evidence stays unknown. Merely visible material does not verify height, coverage or final success.
This tool writes only bounded local visual observations (idempotently) and has no printer/camera I/O, model call or control. Observations live separately from the single-writer telemetry journal, so a worker process cannot overwrite live reports. Their result survives MCP restart and firmware FINISH. A suspect_no_extrusion warning stays active for the job through later unknown/dark/occluded observations and FINISH; only a later clear present observation with a visible footprint at a higher layer may supersede it (without proving final success). It is the first structured progress problem, with the observed layer (physical.observedLayer) and separate wording after firmware completion. A first-layer unknown observation still permits a new assessment at the crossed ten-layer checkpoint (10, 20, …), subject to fresh reports, available geometry and camera visibility. Image interpretation is the client worker’s responsibility: the MCP does not contain an image classifier or pretend pixel change proves extrusion. Clients must consume pending assessments and should never announce a first layer is down from a counter alone. Installing these backend tools alone does not add that worker loop to an older client.
A worker may also fetch the images/geometry and pass up to four calibrated height measurements to this read tool:
{"measurements":[
{"frameId":"saved frame UUID", "visible":true, "observedHeightMm":24, "uncertaintyMm":0.5, "method":"calibrated-height"},
{"frameId":"another saved frame UUID", "visible":true, "observedHeightMm":24, "uncertaintyMm":0.5, "method":"calibrated-height"}
]}
The MCP validates the saved frame identities/times and evaluates these client-supplied measurements; it runs no vision model. Two visible, sufficiently separated expected heights can support consistency, or an unchanged short observed height can support suspect_no_growth. Occluded, out-of-view, uncalibrated, uncertain, stale or contradictory evidence stays unknown. consistent concerns height in those frames only; it does not verify final shape, strength or print success. The assessment returns frame IDs and explicit limitations and is computed without altering the record. There is no automatic stop, pause, resume, model call or printer-setting change.
Sensor limits: Bambu Studio v02.08.02.61 declares P1S lidar calibration unavailable, X1 Carbon lidar calibration available, and H2D calibration/wrapping capabilities. These are capability/configuration facts, not deposited-height measurements. Studio parses xcam detection options and live support bits and AMS air-print capability with firmware exceptions. This feature records reported evidence; it never enables a detector or assumes a capability from a model name.
Validation is offline replay and mocked transports only. No real-printer physical-success claim is made.
camera_stream_start, camera_frame, camera_stream_stop
Development capability; discover these tools before using them with an installed server. Start one shared camera connection while a viewer is open, then request changed frames. The connection closes after 30 seconds without a viewer request. Snapshots reuse its latest frame. A1/P1 use the existing TLS protocol; X1/H2/P2S use one ffmpeg process for the stream lifetime.
{"fps": 1, "idle_timeout_ms": 30000, "bambu_model": "p1s"}
Pass the usual optional host, bambu_serial, and bambu_token overrides to each tool. camera_stream_start returns {status: "started" | "running", transport, fps, startedAt}. Then call camera_frame with, for example, { "since_seq": 0, "wait_ms": 10000, "max_width": 300, "max_bytes": 20000 }. A changed frame returns JPEG base64, seq, dimensions and capture time. Keep the last delivered seq on unchanged; those replies carry no image. max_width preserves aspect ratio; optional max_bytes caps JPEG bytes by downscaling further (base64 adds about one third), and changed_only defaults to true with a 0.02 normalized thumbnail threshold.
Stop requests close the shared connection immediately, affecting every viewer of that printer; normally let idle expiry close it. Other printers keep their own connections. These tools send no motion, heating or print commands. See the camera stream contract for limits, cancellation, availability and lifecycle details.
delete_printer_file
Delete a single file from the printer’s SD card via FTPS. Destructive. Requires confirm: true — without it the call returns status: "skipped" and does not contact the printer. Path traversal segments (..) are rejected. Only files under cache/, timelapse/, and logs/ can be deleted.
{
"filename": "old_print.gcode.3mf",
"confirm": true,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
A bare filename defaults to cache/<filename>. To target other directories pass a relative path:
{ "filename": "timelapse/2026-04-26_12-00.mp4", "confirm": true }
{ "filename": "logs/printer.log", "confirm": true }
upload_gcode
Write G-code content from a string directly to the printer’s cache/ directory. The content is written to a temporary file and uploaded via FTPS.
{
"filename": "calibration.gcode",
"gcode": "G28\nM104 S210\nG1 X100 Y100 Z10 F3000\n",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
upload_file
Upload a local file (G-code or 3MF) to the printer. If print is true and the file is a .gcode file, start_print_job is called automatically after a successful upload. For .3mf files, upload completes normally but you must use print_3mf to initiate the print (which handles plate selection and metadata).
{
"file_path": "/Users/yourname/Downloads/part.3mf",
"filename": "part.3mf",
"print": false,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
start_print_job
Start printing a .gcode file that is already on the printer’s SD card. Do not use this for .3mf files – use print_3mf instead, which handles the project_file MQTT command with proper metadata.
{
"filename": "cache/calibration.gcode",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
If filename does not include a directory prefix, the server prepends cache/ automatically.
cancel_print
Cancel the currently running print job. Sends Bambu Studio’s stop, {"print":{"command":"stop","param":"","sequence_id":"<n>"}}, at MQTT QoS 1, and waits up to 10 seconds for the printer to acknowledge it. A stop that isn’t acknowledged returns an error, and its MQTT client is closed so it can’t be sent late. Not resumable — use pause_print if you may want to continue.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
pause_print
Pause the currently running print job. Sends an UpdateState MQTT command with state: "pause". Resumable via resume_print.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
resume_print
Resume a paused print job that this server inspected and started. Resume reheats and moves the printer, so it is checked like a print start:
- A fresh report must show that job paused, with the inspected nozzle and filament still in place.
- The server downloads the job’s file from the printer over FTPS and compares its SHA-256 with the inspected bytes. A P1S deletes an uploaded project once it starts printing and keeps the plate G-code it extracted,
cache/<name>_plate_<n>.gcode, which is byte-identical to the 3MF’s Metadata/plate_<n>.gcode. When the project is gone, the server compares that file with the inspected plate. A different file refuses the resume, and the job can no longer be resumed from here.
- The resume starts without a prompt when the bytes were verified. Only a file that could not be re-read asks a person; that prompt names the job, its peak temperatures, materials and SHA-256.
- The printer is read again, and on X2D and H2 the native helper rechecks it once more right before sending. Only then does the server send
UpdateState with state: "resume".
The server keeps one resume record per printer. Cancelling the job ends it, and so does a report that the job finished, failed or went idle after it was seen running, or another job seen in its place. A later job with the same name, such as the same file reprinted from the touchscreen, is never resumed. The server watches every MQTT report it receives, not just its own reads. It doesn’t see reports while its MQTT session is disconnected.
The result is {status, message, jobName, bytesVerified}, where jobName is the name counterpart_print_progress reports. On the BambuNetwork and X2D native routes, Bambu’s plug-in puts the file on the printer, so its FTPS path isn’t verified. If the file can’t be read back there, the resume matches the job by its unique name and returns bytesVerified: false, and a person is asked, with the prompt saying so. On every other route, a file that can’t be re-read refuses the resume.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
clear_hms_errors
Clear HMS or print error state on the printer. Sends Bambu’s clean_print_error MQTT command.
{
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_print_speed
Set the active print speed mode. Accepted mode values are silent, standard, sport, ludicrous, or their numeric equivalents 1, 2, 3, and 4.
{
"mode": "sport",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_airduct_mode
Set H2/P2 airduct mode to cooling or heating. This is intended for supported printers only.
{
"mode": "cooling",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
reread_ams_rfid
Trigger a Bambu AMS RFID re-read for one AMS slot. This can move AMS filament; use it only when the printer is idle and unloaded.
{
"ams_id": 0,
"slot_id": 1,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_temperature
Set a checked target temperature for the bed or nozzle through MQTT. Positive targets require the printer model and fresh matching printer telemetry; nozzle heating also requires the declared loaded material and matching nozzle_diameter (default 0.4). Independent model/component and material ceilings apply. A target of zero turns the heater off without requiring material or nozzle metadata. Accepted component values are bed, nozzle, extruder, tool, and tool0.
Manual nozzle heating checks the reported currently loaded AMS tray or external spool. It refuses ambiguous active-nozzle/material selection on multi-nozzle printers; use a checked sliced job or the printer’s own controls there. Stop and heater-off commands cancel pending server print/heating operations. Resuming through MCP requires the same paused job inspected and started by this server instance, with fresh matching telemetry; other paused jobs remain controllable at the printer.
{
"component": "nozzle",
"temperature": 220,
"bambu_model": "p1s",
"material": "PLA",
"nozzle_diameter": 0.4,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_fan_speed
Set a printer fan speed from 0 to 100 percent. Accepted fan values are part, auxiliary, chamber, 1, 2, and 3.
{
"fan": "chamber",
"speed": 40,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_light
Set a printer light node mode. Common Bambu firmware reports the chamber light as chamber_light; valid modes are on, off, and flashing.
{
"light": "chamber_light",
"mode": "on",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
skip_objects
Skip specific object IDs during a running multi-object print. Use list_3mf_plate_objects on the sliced 3MF to find the IDs first.
{
"object_ids": [6495, 6496],
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
set_ams_drying
Start or stop the AMS filament drying cycle on heated AMS units (AMS Pro / AMS-HT). The action parameter accepts start or stop. The ams_id must be an integer from 0 to 3.
{
"action": "start",
"ams_id": 0,
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token"
}
To stop drying:
{
"action": "stop",
"ams_id": 0
}
inspect_print_file
Inspect a prepared sliced 3MF or textual G-code file offline before deciding what to export or print. This tool copies the file into a private read-only snapshot and reuses the same archive, selected-plate, model/nozzle/material and temperature checks used by print preflight. It never contacts a printer or auto-slices an unsliced project.
{
"file_path": "/path/to/bracket.gcode.3mf",
"bambu_model": "p1s",
"plate_index": 0,
"nozzle_diameters": [0.4],
"bed_type": "textured_plate"
}
file_path and explicit bambu_model are required; the model is never inferred from configuration. plate_index is zero-based and defaults to 0. Nozzle/bed checks are optional comparisons against file declarations, not observations of installed hardware. Only these five argument names are accepted; credentials, host and executable/bridge overrides are not part of this tool.
The generic result has receipt_version: "1", evidence: "file-only", dispatch_authorized: false, artifact (sha256, byte_length, file_format), the requested selection, and the original inspection including declared model, nozzles, materials/used filament positions, internal plate path and checked temperature peaks. Hash and byte length identify the exact inspected snapshot; a consumer must compare them with its own artifact and selected plate. The temporary snapshot is removed, and its path is not a dispatch capability. The receipt does not prove printer readiness, physical material/nozzle contents, fit, full motion simulation or permission to print. Actual print routes still independently inspect the dispatched snapshot and require fresh hardware state.
Print options
Every print route sends the options Bambu Studio’s Send dialog sends (Bambu Studio 02.08.02.61, SelectMachine.cpp:3344-3356): bed leveling, flow calibration and nozzle offset calibration, vibration calibration, first-layer inspection and extruder_cali_manual_mode. That covers the BambuNetwork bridge, the native helper and LAN project_file. Each option you don’t pass resolves as Studio resolves it:
- Studio’s saved choice for that printer type in
BambuStudio.conf, if the printer offers it. For example, a P1S offers only on/off for bed leveling, so a saved “auto” counts as unset.
- Otherwise “auto” if the printer offers it, else “on”. On a P1S, flow calibration and nozzle offset calibration are hidden, so they stay “auto”.
Studio hard-codes vibration calibration off, first-layer inspection on and extruder_cali_manual_mode 0. For a P1S with nothing passed, the bridge sends task_bed_leveling: true, auto_bed_leveling: 1, task_flow_cali: false, auto_flow_cali: 2, task_vibration_cali: false, task_layer_inspect: true, auto_offset_cali: 2 and extruder_cali_manual_mode: 0. An option you pass wins. bed_leveling/flow_calibration set “on” or “off”, and auto_bed_leveling, auto_flow_cali and auto_offset_cali take 0 (off), 1 (on) or 2 (auto). On the H2/P2S LAN project_file route, the printer only receives flow calibration as on or off: no verified field requests “auto”, so “auto” sends off, as before. The BambuNetwork and native routes carry auto_flow_cali. Only the printer type’s own section of BambuStudio.conf is read; the file also holds access codes. BAMBU_STUDIO_CONFIG names another file, and an empty value uses no saved choices.
print_3mf
The primary tool for starting a Bambu print. Recommended input: a pre-sliced .gcode.3mf exported from FULU OrcaSlicer-bambulab, OrcaSlicer, or Bambu Studio — see slicing guide. This tool handles the complete workflow:
- Checks whether the 3MF contains embedded G-code (
Metadata/plate_<n>.gcode entries).
- If no G-code is found, attempts to auto-slice via the configured slicer. Profile preparation or slicing failures stop the operation before upload. See the slicing guide for tested CLI versions and combinations.
- Parses the sliced 3MF to extract the correct plate file and compute its MD5 hash.
- Reads slicer metadata and any explicit AMS selection to build the filament mapping.
- Uploads via
basic-ftp to the model-specific location: SD root for H2/full-size A1, cache/ for P1/X1/A1 mini/P2S. X2D print_3mf instead uses its checked native route on macOS or Linux, which stores the job on a ready SD card or USB stick and otherwise on internal storage (eMMC).
- Sends the correct MQTT print command for the target printer family. For H2S/H2D/H2C that means
project_file with project-
评论