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_slotstrays[].display_name,trays[].tray_color,trays[].remain_percenttrays[].resolved_profile_pathtrays[].profile_resolution:exact-model-nozzle,model,generic, orunresolvedtrays[].match_confidence:high,medium,low, ornonerecommended.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 withintimeout_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'svideo.mdbut 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.
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'sMetadata/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
UpdateStatewithstate: "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>.gcodeentries). - 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-ftpto the model-specific location: SD root for H2/full-size A1,cache/for P1/X1/A1 mini/P2S. X2Dprint_3mfinstead 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_filewith project-lengthams_mapping, parallelams_mapping2, and H2-compatible calibration flags.
{
"three_mf_path": "/Users/yourname/Downloads/bracket.3mf",
"bambu_model": "p1s",
"bed_type": "textured_plate",
"host": "192.168.1.100",
"bambu_serial": "01P00A123456789",
"bambu_token": "your_access_token",
"bed_leveling": true,
"flow_calibration": true,
"vibration_calibration": true,
"timelapse": false,
"use_ams": true,
"ams_mapping": [0, 1]
}bambu_model is required for model-specific routing and preset selection. It does not by itself validate pre-sliced G-code. BambuStudio, FULU, and Orca CLI preparation additionally require the exact model/nozzle machine preset and reject incomplete profiles. Using the wrong model can damage hardware. If bambu_model is not provided in the tool call and BAMBU_MODEL is not set in the environment, the server will ask you interactively via MCP elicitation (if your client supports it) or return a clear error.
bed_type defaults to textured_plate if omitted. nozzle_type (stainless_steel, hardened_steel, tungsten_carbide, brass; default BAMBU_NOZZLE_TYPE) sets the installed nozzle when the project must be auto-sliced; the job's nozzle type must match the printer's report, and stock P1S/P1P/A1 presets assume stainless steel. nozzle_volume_type (standard, high_flow; default BAMBU_NOZZLE_VOLUME_TYPE) likewise sets the installed nozzle's flow type for auto-slicing; it must match the printer's reported nozzle flow. After an MQTT print command the server listens to the printer's pushed reports for up to 15 seconds (BAMBU_DISPATCH_CHECK_MS) and returns dispatch: "started" or "unconfirmed"; if firmware 01.08.05+ refuses the command (HMS 0500-0500-0001-0007, needs LAN Only Mode and Developer Mode), the call fails and says so; clear that fatal HMS entry with clear_hms_errors before printing again. ams_slots is the preferred override input; ams_mapping remains the raw escape hatch. On AMS-equipped H2 printers, use_ams: false does not suppress mapping lookup if the sliced file declares filaments. If no mapping is provided for an H2 pre-sliced job with declared filaments, the server fails before sending; pass explicit ams_slots, raw ams_mapping, or auto_match_ams: true.
Set auto_match_ams: true to match the sliced 3MF's tray_info_idx values against the live AMS inventory and use the matching ams_slots. The matcher joins on (tray_info_idx, tray_color) and tracks already-claimed slots, so prints with two filaments of the same SKU but different colors (e.g. two GFG02 PETG HF in black and white) resolve correctly. Falls back to SKU-only when the 3MF's filament has no color set or only one tray of that SKU is loaded. Returns a structured missing report (reason: "no_loaded_match" | "color_mismatch" | "exhausted" | "no_sku") when a filament can't be resolved. Ignored when you provide ams_slots or ams_mapping explicitly.
Layer height, nozzle temperature, and other slicer parameters cannot be overridden via this tool -- they are baked into the 3MF's G-code at slice time. Apply those settings in your slicer before generating the 3MF.
For the optional FULU bridge, set connection_mode: "bambu_network" and explicitly choose connection_type: "cloud" or "lan"; see FULU setup. A successful command submission is not proof that the printer accepted it: inspect printer state, HMS errors, and the printer itself.
bambu_network_bridge_status
Inspect the configured FULU bridge without starting it using {}. Use {"connect": true} to launch the host, handshake, and initialize an agent. See bridge probes for interpreting the result.
bambu_network_call
Call an allowed read-only probe such as {"method": "net.is_user_login", "payload": {}}. The default injects the initialized agent; use with_agent: false for bridge.handshake. Raw printer mutations and unknown methods are refused; use the dedicated checked print or printer tools.
X2D native transport (macOS)
Install Bambu Studio and its networking plug-in, plus the Apple command-line developer tools (clang++). The plug-in is loaded at runtime and is not redistributed. In the installed bambu-printer-mcp package directory, run npm run build:native. For a global install, locate that directory with npm root -g; for an extracted desktop extension, run the same command in the extension directory. Rebuild after updating the package. For Linux, see X2D native transport (Linux); Windows can use status and slicing only.
The npm package and desktop bundle include native/bambu-native-print.cpp, scripts/build-bambu-native.sh and the Linux setup script, never a developer's compiled binary. The server finds the built helper relative to its installed package, regardless of the launch directory. A trusted server setting BAMBU_NATIVE_HELPER can select an alternate executable.
For X2D, print_3mf defaults to connection_mode: "bambu_native"; legacy lan_mqtt_ftps requests are redirected to it. Supply ams_slots, a complete project-level ams_mapping, or auto_match_ams: true. A job that uses only one external spool requires explicit use_ams: false; a job mixing AMS trays with the external spools maps them as 254 (left/deputy nozzle) and 255 (right/main nozzle). Raw ams_mapping2 and nozzle/extra-option overrides are rejected before dispatch; the server derives both AMS representations from the checked structured mapping. Model/nozzle/material inspection and fresh printer-state checks apply before the helper receives a private snapshot. The native helper requests fresh shared printer-state authorization immediately before each print submission, including a certificate retry, and before checked heating, resume, or error-clearing commands; custom helpers must support this handshake. Stop and heater-off remain available without preflight. Native upload-only requests use the same all-plate inspection as FTPS uploads. They accept project_name, preset_name, bed_type, and an existing plate_index; AMS, nozzle, and calibration print options are rejected. Use print_3mf for checked print settings.
The helper waits for connection/certificate exchange and retries only the initial -4030 send once. Rebuild the helper after upgrading to receive the teardown fix. A successful dispatch receipt ends the helper before plug-in cleanup can turn an accepted job into an error. If an older/custom helper crashes after dispatch, the server reports uncertainty: check the printer state and job name before retrying, because resending can duplicate a print. Previous hardware testing reached RUNNING on X2D; this revision is validated with mocked transport regressions and clean installs, not a new physical print. bambu_connect is an optional macOS handoff for user review in Bambu Connect and does not start a print. Native task, heater, and error controls retain the common safety checks; raw controls cannot bypass them. Request cancellation, stop, and heater-off interrupt pending native helpers; the server waits for process exit before releasing a checked file. A command already sent to the printer cannot be recalled by cancelling the request, so verify printer state before retrying.
X2D native transport (Linux)
On x86-64 Linux, one command builds the helper and installs Bambu's networking plug-in and the Bambu Studio certificates. It needs a C++ compiler (g++ or clang++) and network access; no desktop or slicer is required:
npx -y -p bambu-printer-mcp bambu-printer-mcp-native-setupUse the same package version as the server, for example bambu-printer-mcp@1.2.3; when the installation is missing or stale, the server's error names the exact command. The setup downloads the Linux plug-in that Bambu Studio itself installs, pinned to an exact version and SHA-256, and stores it with the certificates under ~/.config/bambu-printer-mcp/bambu-native (BAMBU_NATIVE_HOME or XDG_CONFIG_HOME move it; set the same value for the server). The plug-in is not redistributed by this package, and Bambu Studio's own auto-updating copy is never used. The server finds the installation automatically and passes the plug-in and certificate paths to the helper. Rerun the setup with the server's package version after upgrading: the server refuses a helper built from another version. Only missing or changed files are downloaded again. The setup then loads the plug-in once, offline, so missing system libraries are reported during installation rather than on a stop command. --verify repeats these checks without network access. On Linux the server uses only this managed helper or BAMBU_NATIVE_HELPER; a package-local npm run build:native binary is not used.
--check-update asks Bambu's plug-in service for the newest Linux plug-in and compares the PrintParams layout in the matching Bambu Studio header with the helper. It reports only: the setup never installs an unpinned plug-in, because a changed layout would send wrong print parameters. A pin is raised by a package release after the check passes and the offered archive and required libraries are checksum-verified. Offline plug-in loading and physical X2D printing are separate validation steps, reported with each release.
Once the helper, plug-in and certificates are installed, X2D printing, upload and controls use the same routing, safety checks and authorization handshake described for macOS above. On Linux, stop and heater-off go out over the native route and MQTT at the same time, so a stuck helper cannot delay them. MQTT is sent again once every older print or heating helper for that printer has exited and the immediate MQTT attempt has settled, so none can dispatch after it; either the native route or that later MQTT send succeeding counts, and the result lists all sends under routes. Each MQTT send gives up after 15 seconds (BAMBU_EMERGENCY_MQTT_TIMEOUT_MS), so an unreachable MQTT connection cannot hold back a stop the native route already sent. A connection completing after that deadline cannot dispatch its expired command; an already queued MQTT publish is discarded by force-closing and invalidating that client. A repeated stop or heater-off is harmless. macOS keeps its native-only route. On both systems a print goes to the printer's SD card or USB stick when the printer reports one ready, so it can be reprinted from the printer and archived by tools that read the card; otherwise it goes to internal storage (eMMC), as Bambu Studio's Print button always does. BAMBU_NATIVE_TRY_EMMC_PRINT=1 (or 0) forces the choice. The server accepts only the pinned plug-in checksums; BAMBU_NATIVE_ALLOW_UNPINNED_PLUGIN=1 is a trusted override for testing another build at your own risk. Without a complete installation, Linux keeps its previous behavior: X2D status and slicing work, stop, pause and heater-off use MQTT, and native print requests name the setup command before contacting the printer. Bambu publishes the Linux plug-in for x86-64 only; other architectures keep the MQTT behavior.
x2d_native_control
This optional X2D metadata tool accepts ams_filament_setting and extrusion_cali_sel, plus the read-only queries extrusion_cali_get, extrusion_cali_get_result, and flowrate_get_result. It validates command fields, numeric metadata, and AMS unit/slot selection. Motion, filament loading, heating, safety-setting changes, and task control are not exposed through raw JSON; use the dedicated checked tools where available. A metadata declaration does not verify the physical spool contents.
print_3mf_bambu_network
Submit a sliced project through FULU's separately configured networking runtime. connection_type defaults to cloud. Both cloud and LAN bridge jobs require a printer IP, LAN access code, matching serial/device ID, and fresh MQTT safety telemetry. File, raw AMS/nozzle mapping, and extra-option overrides cannot replace checked parameters. See print examples and AMS requirements. A zero bridge return code confirms submission, not a physical print or direct X2D support.
resolve_3mf_ams_slots
Dry-run the AMS match without uploading or starting a print. The tool reads Metadata/plate_<n>.json and Metadata/slice_info.config, then compares required tray_info_idx values against live AMS trays.
{
"three_mf_path": "/Users/yourname/Downloads/bracket.gcode.3mf",
"bambu_model": "h2d",
"host": "192.168.1.100",
"bambu_serial": "094...",
"bambu_token": "your_access_token"
}list_3mf_plates
List a designer's 3MF plates as Bambu Studio shows them when the file is opened, before slicing. A downloaded kit's six plates are six plates here too. For each plate it gives index (from 0, so slice_stl's slice_plate is index + 1), name, the objects on it, and sliced (whether the file already holds its G-code). It also gives plate_count and the file's title, designer and licence when they're set. A plain 3MF with no plate metadata is one plate. include_thumbnails adds each plate's own preview from the file. Read-only.
{
"three_mf_path": "/Users/yourname/Downloads/kit.3mf",
"include_thumbnails": true
}list_3mf_plate_objects
List the objects of a sliced 3MF plate that the printer can skip, one per copy, with each copy's identify_id from Metadata/slice_info.config, as Bambu Studio's skip dialog lists them. Use this before skip_objects so you pass real Bambu object IDs instead of display-order guesses.
{
"three_mf_path": "/Users/yourname/Downloads/bracket.gcode.3mf",
"plate_index": 0
}print_collar_charm
High-level wrapper for a prepared two-part dog-collar-charm workflow. This tool is intentionally specialized: it expects a prepared two-part charm project and applies a fixed tray policy.
- Smaller inner object -> black -> AMS 1 slot 1
- Larger outer object -> white -> AMS 2 slot 1
The tool will:
- Resolve a local
.3mfortemplate_name. - Auto-slice if the 3MF is still an unsliced project.
- Inspect
Metadata/plate_1.jsonto identify the smaller inner part and larger outer part. - Preflight the required AMS trays on the printer.
- Dispatch the print through the existing H2-safe
print3mfpath usingams_slots.
{
"template_name": "collars/letter_charm_a",
"bambu_model": "h2d",
"host": "192.168.1.100",
"bambu_serial": "03W09C123456789",
"bambu_token": "your_access_token",
"bed_leveling": true,
"flow_calibration": true,
"vibration_calibration": true,
"timelapse": false
}You can also pass source_path directly instead of template_name.
This wrapper currently assumes:
- the input is a prepared two-part charm
.3mf, not a bare STL that needs color-region generation - the selected plate has exactly 2 objects
- the selected plate has exactly 2 used filament positions
- the smaller object is the inner insert/letter and the larger object is the outer body
If the project does not match those assumptions, the tool fails fast with a structured error instead of guessing. The role-to-color and color-to-tray mapping is isolated in code so the next version can evolve toward customer-requested colors without replacing the whole wrapper.
Counterpart tools (counterpart/1)
Counterpart (Scan to Make) reads printers through a small contract that this server and mcp-3D-printer-server share. Each tool declares an outputSchema and returns structuredContent, plus the same JSON as text for older clients. An error is returned as text only, because MCP clients check structuredContent against the schema even on errors. Other tools return an error's details in structuredContent (status, retryable, suggestion, message). When the printer refuses a print, the error also carries a stable code: printer-command-rejected, printer-not-ready, or printer-upload-failed when the file didn't reach the printer and no print command was sent, so a client can act on the code rather than the wording. A print_3mf call made with a progress token reports its LAN upload as MCP progress: progress is bytes sent, total the file's bytes, and _meta["counterpart/stage"] is "upload", at most once per whole percent. counterpart_printer_info reports capabilities.slicing (supports, copies, orient), so a client can offer those choices without knowing the slicer. counterpart_printer_info and counterpart_print_progress take the usual optional host, bambu_serial, bambu_token and bambu_model (default BAMBU_MODEL) arguments.
counterpart_printer_inforeturns{contract, server: {name, version}, printer: {kind: "bambu", model, serial, host}, capabilities}.capabilitieslists progress, layers, the camera transport (bambu-tcpfor A1/P1,rtspfor X1, P2S, H2 and X2D,nonewithout a model),cameraStream: truefor supported camera models,filaments: "ams", pause, resume, cancel,print3mfandgcode(false on X2D). It sends nothing to the printer and never returns the access code.counterpart_print_routereads or changes how prints and Stop/Pause/Resume reach the printer:{route, mode, type, choices, savedTo}, whererouteislan(the local network, in the configuredBAMBU_DEFAULT_CONNECTION_MODE) orcloud(Bambu Cloud through the FULU bridge). Passrouteto change it; the next print and control use it at once, and it is written to the.envin the server's working directory when one exists (savedTo, otherwisenull). It is not part of the shared contract: it has nooutputSchema, and mcp-3D-printer-server has no Bambu Cloud route.counterpart_print_progressreturns{contract, observedAt, state, job?, temps?, activeFilament?, problems}from the printer's MQTT reports, which this server keeps while it is connected. A held session is answered from that cache without any printer traffic, andobservedAtis when the printer sent the report. The server asks the printer for a full report only to fill an empty cache, and at most once every five minutes after the printer has been quiet that long. A printer that sends no report within 8 seconds isoffline.state:IDLEisidle,PREPARE/SLICINGpreparing,RUNNINGprinting,PAUSEpaused,FINISHfinishedandFAILEDfailed. AFAILEDjob with0300400C("The task was canceled.") inprint_error, or in X2D'sfail_reason, iscancelled. Any other or missinggcode_stateon a connected printer isbusy.job(not for idle, busy or offline):nameissubtask_name, else the basename ofgcode_file(a raw G-code print reports only its file path; that basename is thejobNamethe print returns);idistask_id, omitted when it is the LAN placeholder"0";progressismc_percent;remainingSecismc_remaining_time(minutes) × 60;layer/totalLayersappear once the printer reports a total;stageis Bambu Studio's words forstg_cur("Heatbed preheating", "Auto bed leveling").temps: nozzle and bed{actual, target}, andchamberfrom the H2 chamber controller or the X1 sensor. On H2 and X2D the nozzle is the active extruder's, fromdevice.extruder. P1 and A1 printers have no chamber sensor, so it is omitted.activeFilament: the loaded spool'smaterialand#RRGGBBcolor.slotis the indexams_slotsuses:amsId × 4 + trayfor an AMS, the unit id (128 and up) for an AMS-HT, and"ext"for the external spool, or"254"(left) /"255"(right) on dual-nozzle H2D, H2C and X2D. On H2 and X2D it comes from the active extruder's report.problems: a non-zeroprint_erroras 8 hex digits, such as07008011, and each HMS entry asAAAA_BBBB_CCCC_DDDD, such as0300_1800_0001_0003. Severity follows Bambu's HMS level: fatal isfatal, seriouserror, commonwarningand infoinfo. Each HMS problem links to Bambu's page for that code. Messages come from the English HMS tables bundled with the pinned Bambu Studio release;scripts/generate-hms-messages.mjsturns them intosrc/safety/hms-messages.tsand the stage words intosrc/printers/bambu-stages.ts. A model without its own table, such as the P1S, gets the text the other tables share. A code none of them has falls back to the user's own Bambu Studio download:hms_en_<serial prefix>.json, thenhms_en.json, in thehmsfolder next toBambuStudio.conf(seeBAMBU_STUDIO_CONFIG). Those files are read only, and Bambu's text is passed through unchanged. Codes that Bambu lists for a printer without text are reported asinfo.
counterpart_discover_printerslistens for Bambu printers' own SSDP announcements on UDP 2021 forduration_ms(default 4000, 500–15000) and sends one M-SEARCH:{contract, network, printers: [{kind: "bambu", source: "ssdp", name, host, serial, model?, firmware?}]}.modelis thebambu_modelvalue the announced DevModel or the serial prefix names (none for the X1, whichbambu_modeldoesn't take). An announcement counts only from a private IPv4 address that names itself as itsLocation.networkisunavailablewhen another app (Bambu Studio) holds the port. It never connects to or authenticates with a printer.counterpart_setup_fieldssays what this server needs to drive a printer, so a client can offer setup without printer tables of its own:{contract, server, kinds: [{kind: "bambu", label, env, fields}], model?}. Each field names its form role (host,serial,model,secret), the.envvariable to write (PRINTER_HOST,BAMBU_SERIAL,BAMBU_MODEL,BAMBU_TOKEN) and its olderaliases, which this server reads first (a client writing the variable removes them), a label and hint, and whether it is required. The model field lists thebambu_modelchoices with Bambu's names andfromSerial, the model each three-character serial prefix names. Passserialto get that model asmodel.slicerreports the slicer this server would run (type, path, whether it is there, and the Bambu profiles folder) with theSLICER_TYPE,SLICER_PATH(input: "path") andBAMBU_PROFILES_ROOTfields, each required only when what it defaults to is missing. It sends nothing to a printer and returns no secret.counterpart_propose_filamentsproposes which loaded AMS spool prints each of a model's colours, before slicing. Passfilaments(index,name,colour#RRGGBB,material), thepaintedslots no part names,sliced: truefor an already-sliced file and, at print time, the person'schosenspools. It reads the live AMS once and returns:trays: the spools to choose from, each withlabel(A2, as Bambu Studio labels trays),name(Bambu Studio's colour name and the product, "Sunflower Yellow PLA Basic", from the configured slicer'sfilaments_color_codes.json),colour,material,filamentId,feed,sliceableand, when one resolves,profile(the filament profile pathslice_stltakes inload_filaments). An unsliced model lists only spools with a filament profile.proposal: per filament, the nearest spool in OKLab colour with the asked-for material preferred, and averdict:same-colour(within 0.08),closest(that colour isn't loaded;notesays so, "White isn't loaded. Closest loaded: A2 Sunflower Yellow PLA Basic."),no-colourornone. A sliced file's material is a hard rule. One print feeds from onefeed.mapping: every filament slot, painted ones included, to its spool, when the proposal or the person's choice can print;problems(code,message,index) says why not, such asspool-changed,sliced-material,mixed-feedsormaterial-not-loaded.
get_printer_filamentstrays carry the samelabeland person-readablespool_name.counterpart_make_3mftakes{parts: [{stl_path, name, filament?}], out_path}and writes a new 3MF for multi-colour printing. The parts become one assembly: they keep their relative positions, and each part prints with its own filament number (by default part 1 uses filament 1, part 2 filament 2, and so on). Slice it withslice_stland oneload_filamentsprofile per filament number, then print it withprint_3mfandams_slotsorams_mapping. The file holds one assembly rather than one object per part, because Bambu Studio 02.08.02.61's CLI arranges separate objects apart, reports G-code path conflicts between stacked objects when arranging is off, and refusesload_filament_idsfor 3MF input. It never overwrites a file. The result listspath,objects,filaments(the highest filament number) and each part's triangle count.
print_3mf also returns subtaskName, the subtask_name it sends with the job, when it starts a 3MF with the LAN project_file command: an STL or 3MF sliced by slice_stl, and any 3MF on H2, P2S and A1. On H2 and P2S it also returns taskId, the task_id sent with the job; other models send task_id: "0". A client can match counterpart_print_progress reports to its own print with these. Pre-sliced .gcode.3mf files on P1, X1 and A1 mini (sent as a G-code file), the X2D native route, and the BambuNetwork and Bambu Connect routes return neither.