Changelog
[1.2.69] – 2026-11-11
Changed
fdm_designsays when and how a design agent researches before designing or asking: whenever the request names something that exists outside the person's hands (a product, a vehicle and year, a case, a standard part, a mounting place) or a decision turns on a fact about the world; six short steps (list the deciding facts, search each by exact name and generation, read the page not the snippet, rephrase before writing "not found", keep each value with its source, design around what stays unknown) sized to take a few minutes with any model that has web tools; and never to ask the person for what a search answers. Prompt text only; checked with the design-guidance tests; no printer contacted.
[1.2.68] – 2026-11-11
Fixed
- The fit guidance (
fdm_fit,guidance://fdm/fit-by-function) derives a pocket's corners by offsetting the object's outline by the clearance. It used to say "at least the object's own radius", and a rounder pocket corner cuts into the object's corner even when the flats clear. Prompt text only; checked with the design-guidance tests; no printer contacted.
[1.2.67] – 2026-11-11
Added
- Serves two new design prompts and strengthens the everyday guidance.
fdm_fit(also the resourceguidance://fdm/fit-by-function) tells a design agent to choose each fit by what the interface has to do, never one clearance for every interface, keeping the object's size and uncertainty, the print correction, and the fit apart, with cited starting clearances and mechanisms that absorb uncertainty.fdm_flexurescovers parts that flex, grip, snap, clip, spring, or hold something: compliant architectures, strain chosen by duty (once, daily, held bent), material and layer direction as planning bands, bite at the forced opening, heat and creep, and ease of use as a check equal to the hold (where the fingers go, the force to open, one-handed loading).fdm_designnow carries the same judgement in short form for every task, including looking up published dimensions before asking, treating an unedited prefilled size as no measurement, designing to a cased product's size rather than the bare product's, fitting an object in its stiffest and largest state, treating printed screws at hand sizes as an ordinary choice with threads kept out of the main load path, and stating "prints without supports", "holds", or "fits" only with the engine check or slice number.fdm_assembly,fdm_after_sliceandcad_designgain the matching fastener, review and parameter rules. The server'sinstructionssay when to add each prompt. Supersedes the fit-by-function resource drafts by serving the fit text as a prompt as well, so prompt-only design workers read it. Validated with the design-guidance and CAD protocol tests against mocked transports; no printer contacted and no physical fit or print claimed. Prompt text only; no tool, slicing, or print behavior changes.
[1.2.66] – 2026-11-10
Fixed
- Allow a full-size Bambu A1 to start a checked job after a stopped job reports
FAILED,print_type: idle, zero print error, empty HMS and a named prior job. Port Rowan McMahon’s A1 recovery contribution; retain fresh identity/nozzle checks and rejection of incomplete reports, active jobs and other models. Validated with mocked status regressions; A1 firmware evidence comes from the contributor, with no new physical test. - Update Axios to 1.21.1 and basic-ftp to 6.2.6, including their upstream redirect-header and directory-download fixes. Keep bambu-node pinned.
[1.2.65] – 2026-11-10
Fixed
- Bambu Studio no longer hangs until
SLICER_TIMEOUT_MSon a Mac where it once crashed. OrcaSlicer and FULU's OrcaSlicer-bambulab launch the same way and get the same change. The CLI opens a hidden window to draw plate thumbnails, which starts AppKit. When the person's crash history (~/Library/Application Support/CrashReporter/BambuStudio_<hardware UUID>.plist) dates a crash inside the app's last window restoration, AppKit raises its modal "reopen windows?" alert. The slicer then waits at 0% CPU, and every slice waited with it; stopping it never answered the alert. On macOS each Bambu-compatible slice now runs with a fresh, emptyCFFIXED_USER_HOMEof its own underTEMP_DIR, removed afterwards, so AppKit finds no crash history. The CLI reads its profiles from its own bundle or from the files this server passes, and sets no data folder without--datadir(Bambu Studio 02.08.02.61src/BambuStudio.cpp), so slices are unchanged. With Bambu Studio 02.08.02.61 on macOS 27.2,plate_1.gcodewas byte-identical between current main launched in a fresh private home and this build, for the same model (57m 47s, 40.78 g). Real-home launches were not compared (they can raise the alert). That the private home changes nothing else rests on the source above and on what was observed: AppKit created onlyLibrary/Application Support/CrashReporterin it, while preferences (cfprefsd ignoresCFFIXED_USER_HOME),HOME,TMPDIRand the saved window state stay the person's own. A home seeded with that crash history hung current main at 0% CPU inNSAlert runModaland sliced on this build in 1.6 s. OrcaSlicer's results were not compared: the installed OrcaSlicer 2.4.0-dev crashed on every slice, before and after. Linux and Windows launches are unchanged. npm testruns the suite throughscripts/test-with-temp-guard.mjsagain, as 1.2.61 introduced it, so a suite that leaves temporary directories behind fails. A merge of the version files in 1.2.62 put back the oldtestscript, so 1.2.62 to 1.2.64 shipped without the guard in the test script. The published code was unaffected: the package doesn't run its test script, and the guard was never part of the package. Test infrastructure only; checked by runningnpm testthrough the guard.
Added
- On macOS, a Bambu-compatible slicer that uses no CPU and writes nothing for
SLICER_STALL_SECONDS(default 20; 0 turns it off) is stopped and reported with the stablestructuredContent.codeslicer-waiting-on-dialog, instead of afterSLICER_TIMEOUT_MS. The message says to open the slicer once, answer what it shows and slice again; nothing is sent to the printer. It carries noslicer_report, because it is no verdict on the model.
[1.2.64] – 2026-11-10
Added
Report CAD installation estimates/measured bytes and coded refusals; queue runs within their own deadlines, retain protected final-result validation records, reuse content-hash input bundles, and reveal preview openings with depth/feature edges. Clarify scan-reference scope and measured-interface precedence. Validated through confined headless fixtures; no physical fit/print or app update.
Add optional confined code-CAD parity with bambu-printer-mcp: cad_status/setup/run/check_fit, cad_design and cad/1, pinned CAD/mesh libraries, protected scan inputs and explicit millimetre/Z-up preparation, independent checks and six renders. CAD_ENABLED=0 hides the family; setup installs only on request and requires internal ownership-enabled macOS storage without re-signing. Validated with stubbed printer transports and headless CAD; no physical print or installed Counterpart update.
[1.2.63] – 2026-11-10
Added
counterpart_setup_fieldssays for each printer kind whethercamera_snapshotreads its camera with only the settings the fields write (cameraSnapshot), as bambu-printer-mcp does. It isfalsefor every kind here. For Bambu,camera_snapshoton this server reads only aPRINTER_CAMERA_SNAPSHOT_URL, which no setup field writes; bambu-printer-mcp reads the printer's own camera. For the other kinds a webcam is an add-on found through the printer's own settings once the server runs (counterpart_printer_inforeports it), not from these fields. A client such as Counterpart can then ask for a camera picture in its setup check only where the MCP says it can, instead of deciding by the printer type's name. Every kind declares it; a client reads it missing as an older server. Checked with the setup-fields tests; no printer contacted.
[1.2.62] – 2026-11-10
Fixed
- Report
printOutcomeinprint_3mf,upload_gcodeandprocess_and_print_stlerrors (counterpart/1):not-sentbefore any print command,unknownafter a possible dispatch, orrejectedwhen the printer refuses it. Fresh MQTT report timeouts no longer make clients guess whether printing started. Request-local tracking covers direct MQTT, FULU and all non-Bambu upload/start boundaries without matching error wording. Verified with mocked transports; no physical print started.
[1.2.61] – 2026-11-10
Fixed
Track checked print snapshots from allocation so server shutdown also removes in-flight copies whose operation has not returned. Verified with an exiting child process and mocked native shutdown; no printer contacted.
Remove test fixture directories at file teardown even after failures or early returns, and run the full Node test suite in a private temporary directory that fails on leftovers. Regression checks cover clean, leaking and failing suites; printer transports are mocked and no printer is contacted.
Remove the server-owned temporary output directory on exit while retaining caller-specified
TEMP_DIRcontents, matching the Bambu fork. Checked through local stdio and HTTP server shutdown tests.On Node 18, an HTTP (
streamable-http) server with a connected client now finishes its SIGTERM/SIGINT shutdown. Node 18'sclose()waits for clients' keep-alive connections (Node 19 and later close idle ones itself), so the server never exited, and a supervisor's later SIGKILL skipped the exit cleanup and left its temporary folder behind. Shutdown now closes the remaining connections. Found by the suite's leftover check in Node 18 CI (five leaked server folders and two timed-out shutdown tests), and checked locally with Node 18.20.8 and 22.
[1.2.60] – 2026-11-08
Fixed
- Drain FULU events after a polling sleep crosses the delivery deadline so a queued printer reply is read before disconnecting. Validated with mocked hosts under CPU load; no physical printer was used.
[1.2.59] – 2026-11-08
Fixed
- Bambu inspection accepts OrcaSlicer 2.5 dual-nozzle singleton
nozzle_volume_typeonly when the selected plate declares both physical extruders and matching variants. Conflicting aliases and incomplete selections still reject, and independent hardware/material temperature limits remain enforced. Verified with synthetic X2D, H2C and H2D archives; no printer contacted. print_3mfdelivers queued upload progress, including the final 100%, before returning its result. Notification failures log to stderr and do not fail the print. Verified through the public MCP handler with mocked dispatch and delayed/failing notifications; no printer contacted.
[1.2.58] – 2026-11-07
Fixed
- A large Bambu
print_3mfupload no longer fails with "Timeout (data socket)" when a P1S's SD card pauses mid-file. The upload now waits up to 120 s for the printer to take more data. FTP commands keep their 15 s limit, so a printer that has really stopped is still reported. With bambu-printer-mcp on Nov 6, an 18.4 MB plate stopped at 13,287,424 bytes for more than 15 s; this server used the same 15 s limit. Checked with a local FTP server that pauses for twice the command timeout partway through a 12 MB file; no printer contacted by this server's tests.
Added
- Bambu
print_3mfreports its LAN upload as MCP progress (counterpart/1) when the call has a progress token:progressis bytes sent,totalthe file's bytes, and_meta["counterpart/stage"]is"upload", at most once per whole percent, as bambu-printer-mcp does. Checked with unit tests and a local FTP server.
[1.2.57] – 2026-11-06
Changed
- When the upload of a
print_3mfjob fails, the error carriescode: "printer-upload-failed"(counterpart/1), as bambu-printer-mcp 1.1.74 does: the file didn't reach the printer and no print command was sent, so a client knows the print did not start. Counterpart had reported such a failure as "could not confirm a print start". This server's upload already streams the file from disk, so it doesn't have bambu-printer-mcp 1.1.73's single-write upload timeout. Checked with the dispatch tests; no printer contacted.
[1.2.56] – 2026-11-06
Added
fusion_mcp_statusreportsactiveDesignwhen Fusion is connected: whether a design is open, read from the Fusion360MCP add-in itself. It calls the add-in's read-onlyget_design_type, which reads the active document's Design product the way every design command does (_design(),addon/server/command_handler.py:310-332and:3555-3563at the pinned86a3016a5a5b). Success means a design is open. The add-in's own error kindNO_ACTIVE_DESIGN(addon/server/hints.py:17-19, rendered as**get_design_type** ERROR (NO_ACTIVE_DESIGN)bysrc/fusion360_mcp/server.py:122) means none is: Fusion is on its Home tab, and the pinned add-in refuses every design command,fusion_mcp_new_designincluded, until one is open (faust issue #12). Any other answer leavesactiveDesignout (unknown). Clients such as Counterpart read this field instead of matching Fusion's error wording. Checked with the bridge's fake Fusion MCP: an open design, no design, another error, and the add-in not answering. Not run against a live Fusion.
[1.2.55] – 2026-11-06
Added
counterpart_setup_fieldsmarks OctoPrint's address fieldinput: "url": it takes a host name or address, or an http or https URL with a path (OctoPrint behind HTTPS or a reverse proxy at a sub-path, whichPRINTER_HOSTaccepts since 1.2.51). A client accepts a URL there and writes it as typed; other kinds' host fields take a host name or address only. Checked with the setup-fields tests; no printer contacted.
[1.2.54] – 2026-11-06
Fixed
list_3mf_platesno longer leaves out a painted filament when a part's mesh is too large to read. A mesh over 64 MiB, or past 256 MiB read in total, used to be taken as unpainted, so a filament painted on it could go unlisted. Such a plate now lists every filament the project declares and saysfilaments_complete: false, so a client offers a spare row rather than miss one that prints. Every other plate saysfilaments_complete: true. A sliced plate is unaffected, even when it shares the unread mesh with an unsliced plate, because Studio's ownplate_N.jsonnames its filaments. Checked with unit tests for the one-file and the total limit.
[1.2.53] – 2026-11-06
Fixed
list_3mf_platesgives each plate itsfilaments: the project filaments that plate prints with, and only those, with each one's colour, material, filament id and the first part using it (counterpart/1). Clients asked people to choose spools for every filament any plate used: on the Kass 3D scan rig's Screws plate, which prints only filament 3, Counterpart also asked for filaments 1 and 2 from other plates. A sliced plate uses Studio's ownplate_N.jsonfilament_ids. An unsliced plate is worked out as Bambu Studio's CLI does (PartPlate::get_extruders_under_cli,PartPlate.cpp:1298-1420;ModelVolume::get_extruders,Model.cpp:3357-3412): each part's filament, its painted facets, including meshes a component keeps in the root model (a component withoutp:path,bbs_3mf.cpp:4131-4148) (decoded asTriangleSelector::deserializereads them,TriangleSelector.cpp:2111-2139), feature filaments, support and raft filaments, layer ranges and the plate's tool changes. A mixed filament counts as the filaments it mixes (PartPlate.cpp:1437-1449). Feature filaments and support follow what the slice applies rather than Studio's plate list where the two differ: a part that names no extruder prints with the project's wall, sparse and solid infill filaments, a part's or object's feature filament counts whether or notseparate_filaments_for_featuresis set (PrintObject.cpp:3105-3150; libslic3r never reads that key), and support and raft resolve one setting at a time, the object's own else the project's (PrintObject.cpp:3052-3063), with support filament 0 following the object (Print.cpp:490-501). Negative parts, support blockers and enforcers, copies that aren't printable (checked per copy, as each build item carries its own flag:bbs_3mf.cpp:4183-4185,PartPlate.cpp:1311-1322) and other plates don't count; a mesh too large to read is taken as unpainted rather than failing the listing. Checked against two projects written by Bambu Studio 02.08.02.61's CLI on a Mac (two plates, three filaments; sliced and unsliced give the same answer as Studio's own slice) and the scan rig's metadata.print_3mfsends a tray only for the filaments the plate prints and -1 for every other project filament, on the LAN and plug-in routes, as Bambu Studio does (SelectMachineDialog::get_ams_mapping_result,SelectMachine.cpp:1463-1500). A caller's project-levelams_mappingwith trays for unused filaments was sent as it was. Checked with unit tests; no printer contacted.
[1.2.52] – 2026-11-06
These port bambu-printer-mcp 1.1.72's fixes from a read of Bambu Studio 02.08.02.61's source. The real Bambu Studio slices named below ran through bambu-printer-mcp's code, which is the same as this release's for these paths; this repo's tests use those Studio-written files.
Fixed
pause_at_layerskeeps a project's own colour changes and pauses. Bambu Studio saves them inMetadata/custom_gcode_per_layer.xml(02.08.02.61bbs_3mf.cpp:184), notcustom_gcode_per_print_z.xml, so they were never read.--load-custom-gcodesreplaces the project's whole map (BambuStudio.cpp:4005-4008), so a requested pause on a designer's file dropped its colour changes and pauses. They are now merged in. Without a pause request nothing is passed: the CLI keeps the project's own entries itself. A pause on a project with more than one plate needsslice_plate, because the CLI carries custom G-code for one plate only. Checked on a Mac with Bambu Studio 02.08.02.61: a project saved with a colour change at 0.6 mm and a pause at 1.0 mm, sliced with a pause before layer 8, kept all three. Slicing only; nothing was printed.- Print safety no longer refuses every Engineering Plate job as "contradictory bed type metadata". Studio writes
eng_plateinplate_N.jsonandEngineering Platein the project settings (PrintConfig.hpp:437-456,PrintConfig.cpp:437-445). Every Studio name and token for each of its five plates now reads as one plate. Checked with a real Bambu Studio 02.08.02.61 Engineering Plate slice, which the previous code refused. - An AMS-HT after the first is addressed as its own unit. Tray 129 is
{ams_id: 129, slot_id: 0}, as Bambu Studio maps it (DevFilaSystem.cpp:367-368,SelectMachine.cpp:1489-1497), instead of slot 1 of unit 128, which doesn't exist. The fresh-state check finds that unit's tray the same way. Checked with unit tests; no printer contacted. - When a slice fails without a usable result.json, the exit code is explained for every code Bambu Studio defines (
libslic3r/Utils.hpp:21-75, 50 codes; 20 before), for example -66 (filaments can't be assigned to the nozzles) and -68 (a filament the nozzle can't print). A test checks the table against Utils.hpp.
Changed
bed_typeacceptssupertack_plate, which slices as Studio's ownSupertack Platebed type. Checked on a Mac with Bambu Studio 02.08.02.61: the slice'splate_1.jsonsayssupertack_plate, the project saysSupertack Plate, and the start G-code heats the bed to the filament's SuperTack temperature (45 °C for PLA). Slicing only; nothing was printed. OrcaSlicer takes the same name but wasn't sliced with it.slice_stl'sskip_objectstakes identify_ids, which the CLI matches against each object copy (BambuStudio.cpp:6530-6545), not positions.list_3mf_platesgives each plate'sinstances: every object copy with itsidentify_idfrommodel_settings.config.
[1.2.51] – 2026-11-06
Added
- OctoPrint:
octoprint_request_api_keygets an API key through OctoPrint's Application Keys approval (the person clicks Allow in OctoPrint), keeping the request open between calls because OctoPrint drops one that isn't polled every 5 seconds.counterpart_setup_fieldsoffers it on OctoPrint's key asobtain, so a client can show an "Approve in OctoPrint" button instead of asking for a pasted key. - OctoPrint:
connect_printerconnects OctoPrint to its printer with OctoPrint's saved port and baud rate, and withpower_onfirst switches the printer on through PSU Control.counterpart_print_progressreportsoctoprint.disconnected(and a switched-off printer) instead of a bare offline, and a refused print says the same. - OctoPrint:
PRINTER_HOSTmay be a URL, for an OctoPrint behind HTTPS or a reverse proxy at a sub-path. The camera's relative and loopback URLs resolve against it as OctoPrint's page does in a browser (/webcam/…from the web server's root,webcam/…under OctoPrint's sub-path). npm run test:octoprint-live: an opt-in check against a real OctoPrint whose only printer is the Virtual Printer (it refuses any other).
Fixed
- PrusaSlicer configs with binary G-code on (Prusa's MK4, MK4S, MINI, XL and CORE One profiles once it is enabled) wrote binary bytes into the
.gcodefile, which inspection then refused.slice_stladds--no-binary-gcodefor such a config, and a slice that still comes out binary stops with an explanation. - OctoPrint file names with spaces or other reserved characters are encoded when a file is read or started.
- OctoPrint's file list is cut to each file's name, path, type, size, date, estimated print time and last print, with folders' children (#4: a 324-file library was 500 KB).
- OctoPrint's cancel, start and temperature calls answer 204 with no body; their results now say what was done instead of being empty.
Checked against OctoPrint 1.11.8 and the 2.1 development build (octoprint/octoprint:canary) in Docker with OctoPrint's Virtual Printer, directly and behind an nginx sub-path proxy, through this server over stdio. The approval was given the way a browser gives it (sign-in, approval page, decision with OctoPrint's CSRF token). PSU Control is checked against a fake OctoPrint only, and PrusaSlicer's binary output with PrusaSlicer 2.8.1's CLI on Linux. No physical printer was used.
[1.2.50] – 2026-11-06
Added
counterpart_setup_fieldsmarks the kind this server runs when a.envsets noPRINTER_TYPEwithdefault: true(OctoPrint, the same fallback the server uses), so a client recognises such a.envwithout a printer table of its own. Checked with the setup-fields tests; no printer contacted.
[1.2.49] – 2026-11-06
Added
list_3mf_plateslists a designer's 3MF plates as Bambu Studio shows them before slicing: plate_count, and for each plate its index, name, objects, whether it is already sliced and, optionally, its own preview from the file. A plain 3MF with no plate metadata, even one with a large mesh, is one plate. Clients show a kit's plates from here instead of readingMetadata/model_settings.configthemselves (Counterpart PRD §8.0 item 9). This ports bambu-printer-mcp 1.1.69. Checked with unit tests, and on real Bambu Studio projects with 6, 12 and 2 plates.
Removed
slice_stl'ssplit_to_platesandcapabilities.slicing.plates(1.2.47). A designer's 3MF already carries its plates, and nothing used the split.
Fixed
- A slice whose result.json says success but writes no printable file reports
slicer_report.failed: true.
[1.2.48] – 2026-11-06
Fixed
fdm_slicingno longer says a print's own request carries the support settings.print_3mf's own slicing of a file that isn't sliced yet takes no support settings and uses the process profile's. The prompt now says a print gets the supports it was sliced with: print the sliced file itself, or slice the print withslice_stland the sameenable_supportandsupport_type. Checked with the prompt tests.
[1.2.47] – 2026-11-06
Added
slice_stlsplit_to_plates: a model bigger than the bed is split across plates. On the Bambu-compatible route, an STL or OBJ that doesn't fit the printer's bed is split into its separate parts, each kept whole. Parts laid out within 20 mm of each other stay together as the designer grouped them, and a part inside another stays with it, where they fit. They are arranged on as many plates as needed, inside the machine preset's printable area, clear of its excluded areas and under its printable height. The result is a deterministic multi-plate project 3MF,bed_split.plates(index,name,objects) and a plain message, and plate 1 (orslice_plate) of that project is sliced. A part larger than the bed is an error that names the part and its size against the bed's.counterpart_printer_inforeportscapabilities.slicing.plates. This ports bambu-printer-mcp 1.1.67. Checked with unit tests and the stand-in slicer; the same module split a real 850 × 521 mm kit STL into 4 plates, each of which Bambu Studio 02.09 on macOS sliced (through bambu-printer-mcp).
Changed
- A slicer's refusal reaches a person as a plain sentence.
slicer_report.messageand the start of a failed slice's text say what is wrong, for example Bambu Studio's and OrcaSlicer's empty-plate, off-plate and too-tall refusals, PrusaSlicer's "outside of the print volume" and CuraEngine's "no non-empty layers", matched on their own strings. The slicer's words stay in the newslicer_report.slicer_messagefor logs. A refusal without a result.json, including from PrusaSlicer and Cura, carries aslicer_reporttoo. A successful slice's warnings are unchanged inmessage.
[1.2.46] – 2026-11-05
Added
fusion_mcp_setupreturnsmessagewhen it isn't ready: what is missing (Fusion itself, the add-in at the pin, the port login item, or this server's Fusion settings, or a.envto write them to) and what to do, in plain words a client shows as they are. Counterpart's Mac app read theno-env-fileoutcome to word that itself. Checked with the setup tests.
[1.2.45] – 2026-11-05
Added
blender_mcp_setupchecks the MCP for Blender add-on that the configured bridge needs, when it is themcp-for-blender(orblender-mcp) package run withuvx: the add-on file Blender loads (for the running Blender's version), its protocol and the one the package expects, whether Blender is listening and the running add-on's ownget_addon_status. It changes nothing. Withupdate: trueit stages the add-on with the package's owninstall-addonat the inspected version, refuses an installed file that isn't a regular local MCP for Blender add-on or a staged one with another protocol, keeps the old file as a backup next to it and renames the new one into place. It never starts, stops or edits Blender. A handshake that can't be read is reported aslive_errorwith the rest of the check. Overlapping updates run one after the other, and a cancelled request stops its installer and changes nothing more (infusion_mcp_setuptoo). Its subprocesses (uvx and the package) get only the login environment and uv's and Blender's settings, never printer access codes or other server secrets. When the add-on can't be checked or updated here it says what to do inmessage.uvx.execounts as uvx on Windows. The running Blender's version folder is found in Blender's macOS, Windows and Linux (~/.config/blender) layouts. Another bridge reportssupported: false. Both tools declare remote scopereadfor a check andrawforupdateorinstall, so no paired device gains the change. Counterpart did this itself; it now comes from the MCP that runs the bridge, as in bambu-printer-mcp. Checked with a stand-inuvxand temporary add-on folders; the same code in bambu-printer-mcp checked the real package (2.2.7) and Blender 5.0 add-on on a Mac, without replacing it.fusion_mcp_setupchecks, and withinstall: trueinstalls on macOS, what the Fusion bridge needs: the Fusion360MCP add-in at the pinned commit (every file checked against its SHA-256; a symlink, an extra file or a changed byte installs nothing) set to run on startup, a login item that gives FusionFUSION_MCP_PORT(installed only when launchd has it loaded), and this server's missingFUSION_MCP_*settings, added to its own.envafter a copy of it. AFUSION_MCP_*setting the process has or the.envgives a value is never rewritten (an empty one, as.env.exampleleavesFUSION_MCP_COMMAND, is filled in), so a configured command or chosen arguments stay, and an add-in already at the pin is left in place. Without a.envit still installs the add-in and the login item and reportsenv: "no-env-file", withreadyfalse until the settings are added. It reports whether Fusion is installed and never starts or quits it. Counterpart's Mac app did this itself. Checked with a synthetic pinned archive and a recordinglaunchctl; the same code in bambu-printer-mcp reported a real Mac's setup ready and installed from the pinned GitHub archive into a temporary home folder.
Changed
- The Fusion bridge's default server (
FUSION_MCP_PINNED_COMMIT) and the add-infusion_mcp_setupinstalls are pinned to one commit,86a3016a5a5bof DMontgomery40/fusion360-mcp-server: faust-machines' server and add-in with the document bindingfusion_mcp_new_design'sbind_documentneeds, while that change is reviewed upstream. Before, the default arguments named faust-machines19b9f1e95192, while Counterpart installed the fork. This server's bridge doesn't use document binding; the fork has all 92 of faust's tool names at19b9f1e95192and addsnew_documentandclose_document(compared from both commits'tools.py; schemas weren't compared). A server configured with onlyFUSION_MCP_COMMANDnow runs the fork; one with its ownFUSION_MCP_ARGSis unchanged.
[1.2.44] – 2026-11-05
Fixed
get_slice_settingslistsnozzle_diameteramong the slice arguments it takes forown_process, so a schema-driven client checks layer heights against the same nozzle as the slice. It already read the argument; clients that send only listed arguments left it out, and a valid 0.42 mm layer for a 0.6 mm nozzle was refused. Checked with a stand-in slicer.
[1.2.43] – 2026-11-05
Fixed
- The FULU container test expected the real path on both sides of the config mount, so
npm testfailed on macOS, where/varis a link to/private/var. The server mounts the real folder at the path the host is given, and the test now expects that. Test only; found when bambu-printer-mcp's macOS CI ran the same test.
[1.2.42] – 2026-11-05
Added
- Every tool declares in
_meta["counterpart/remote"]how a client that offers this server to other devices (Counterpart's remote endpoint) may expose it:scope, the least device scope that may call it (read, design, control, print, raw);raisedBy, a boolean argument that needs more (fusion_mcp_statuslaunch,blender_mcp_statusconnect); andarguments, the names this server's configuration chooses (config, orconfig-topfor the top-level printertype: the printer it targets, its credentials, hardware and programs) and the local files it reads (path) or writes (output). A tool that forwards an open object (an RPC payload, another server's tool arguments) declares every configuration name. A new tool or argument is classed here, with no Counterpart release. A script compared every listed tool's declaration with Counterpart's hand classification (main1b66d937) and found no difference in scope or argument kind, so no paired device gains or loses a tool; the tests check every listed tool has one and hold the name floors. Checked by listing the tools over stdio; no printer. - Every slice this server runs (Bambu Studio and OrcaSlicer CLIs, PrusaSlicer, Slic3r, Cura) keeps each finished slice, and slicing the same model the same way again restores it instead of running the slicer: Print Again, or printing a model a client just estimated, no longer waits for the slicer. A slice is identified by exactly what the slicer was given: its executable (path, size and modification time, so a slicer update slices again), this server's version, and its full argument list with every input file (model, profiles, filaments, generated overrides) replaced by its content hash, so editing any of them slices again. A run whose arguments name any other folder is never kept, nor is a failed slice; every check after the slicer still runs on a restored slice. The newest 16 are kept in
~/.cache/<package>/slices;SLICE_CACHE=offturns it off,SLICE_CACHE_DIRandSLICE_CACHE_ENTRIESmove and size it. Counterpart kept its own copy of this keyed on the server's.env; it can now rely on the server. Presets the slicer finds by itself rather than through its arguments count only through its executable (a slicer update slices again). Checked with a stand-in slicer across a server restart; no real slicer. inspect_print_filereturnssliced: the selected plate'sestimate(seconds,grams, from the slicer's own slice_info.config) andsettings(layer_height_mm,sparse_infill_percent,wall_loops,layer_count, from the 3MF's project settings and plate G-code, or a G-code file's own comments), and the file'splate_count. Slicing tools returnslicer_reportbesideslicer_result:failed,message(the slicer's error and every plate warning, verbatim) andplate_count, on success and on a failed slice. Clients such as Counterpart read these instead of parsing slicer files themselves. Checked with synthetic 3MF and G-code files and recorded Bambu Studio result.json files.
[1.2.41] – 2026-11-05
Changed
get_slice_settings'own_processanswers for the slice a client would make. Withsource_path, the call also takes that slice'sslicer_profile,template_name(its template),template_3mf_path,layer_height,wall_loops,sparse_infill_density,enable_support,support_type,qualityandstrength, asslice_stltakes them, withslicer_typeandbambu_modelas before.own_processis true only when that slice prints the process the 3MF carries, unchanged: a named profile or template replaces it, and an explicit value or a quality or strength other than standard changes it. Clients then pass their own configuration through instead of deciding which settings replace a designer's process. Checked with a stand-in slicer.
[1.2.40] – 2026-11-05
Fixed
- A relative
BAMBU_NETWORK_CONFIG_DIR, per-call config folder orBAMBU_NETWORK_CERT_DIRis made absolute before it is mounted into FULU's container or sent to the host. The host runs from/pluginsin the container, so a relative path pointed it at a folder that wasn't mounted. A certificate folder outside the config folder is created before the mount, so Docker doesn't create it as root. Checked with a stand-indockerrunning the fake FULU host.
[1.2.39] – 2026-11-05
Fixed
fdm_slicingno longer tells a client that PrusaSlicer, Slic3r or Cura generate no supports. They take no support settings fromslice_stlhere, but a profile with supports enabled still generates them, so the text says supports follow the configured profile and to slice a checkpoint before modeling any. Checked with the prompt tests.- Stopping the FULU bridge can no longer hang. With
BAMBU_NETWORK_BRIDGE_IMAGE, the container is stopped (docker stop --time 2) and removed before the server waits for the docker client. The wait for the bridge's shell is bounded, so a descendant that keeps its pipes open no longer blocks shutdown or a restart. Checked with a stand-indockerand with a shell whose background child holds the pipes: 30 s before the fix (until that child exited), 4 s after.
[1.2.38] – 2026-11-05
Fixed
- Every extraction of a 3MF's process settings for slicing gets its own temporary directory, removed when the tool call that made it ends. 1.2.33 named them by content, so two slices of the same project at once still wrote one file, and a write could truncate the file the other slice was reading; nothing removed them either. The path
get_slice_settingsreturns stays, named by content and written whole before it is renamed into place. Checked with concurrent extraction tests and a stand-in slicer.
Changed
get_slice_settingson a 3MF with no slicer settings returnsraw_key_count0 (and noextracted_settings_path) instead of an error, so a client can tell a file with no settings to keep from one that couldn't be read. A file that isn't a readable 3MF, or whose settings file is there but can't be parsed, is still an error. A PrusaSlicer project'sMetadata/Slic3r_PE.configis now read like bambu-printer-mcp reads it, so its settings are reported instead of refused. Counterpart refuses an edit of a designer's 3MF when it can't read the designer's settings, and needs this to allow edits of a 3MF that has none.
[1.2.37] – 2026-11-05
Added
counterpart_discover_printersfinds printers on the local network: Bambu Lab printers from their own SSDP announcements (serial,bambu_modelvalue, name, firmware), and OctoPrint, Klipper (Moonraker) and PrusaLink hosts from their Bonjour adverts. It never connects to a printer; a Bambu port another app holds isnetwork: "unavailable", not "none found". Checked with captured SSDP packets anddns-sd/avahi-browselines; not run against live printers.counterpart_setup_fieldslists everyPRINTER_TYPEthis server drives with the.envsettings it reads for each (address, port, API key or password, and for Bambu the serial, model and access code), the Bambu model choices and the model each serial prefix names. Clients such as Counterpart offer printer setup from it instead of copying this server's tables. It also reports the slicer this server would run (slicer: type, path, whether it is there, and the Bambu profiles folder) with theSLICER_TYPE,SLICER_PATHandBAMBU_PROFILES_ROOTfields, required only when what they default to is missing, so a client can say "Bambu Studio isn't installed" or ask where it is instead of the person editing paths by hand.counterpart_propose_filamentsproposes which loaded spool prints each of a model's colours before slicing, with an explicit verdict and note per part: a colour that isn't loaded says so instead of quietly printing another colour, and a colour that is loaded but not chosen (on the other feed, in another material, or on a spool another colour already prints from) says which. It checks a person's chosen spools against what is loaded now and maps painted slots; a sliced file's painted materials count when it chooses the feed. Each spool carries the filament profileslice_stltakes. An already-sliced file binds each filament to a nozzle, which the proposal can't read yet: on a dual-nozzle printer with both external spools, a mapping onto them is reported asexternal-nozzle-unverifiedinstead of offered. Checked with mocked Bambu reports and fixture profile trees; not printed.
Changed
get_printer_filamentsslots carrylabel("A2", "AMS HT A", "External", "Right external", "Spool") andfilamentId, and a Bambu slot'snameis the spool as a person names it ("Sunflower Yellow PLA Basic", from Bambu Studio'sfilaments_color_codes.json) instead of the raw "PLA Basic PLA #FEC600". An AMS-HT slot'sidis its unit id ("128"), the tray valueprint_3mftakes, instead ofams_id × 4 + tray("512").
[1.2.36] – 2026-11-05
Added
fdm_slicing, a design prompt next tofdm_design: how this server's configured slicer orients a model and generates supports, and how to check a choice with a checkpointslice_stl(readslicer_result; setorient, and always setenable_support, since leaving it out applies the preset's own setting). The text followsSLICER_TYPEand the same rules ascapabilities.slicing: the Bambu-compatible CLI route orients and takes supports; generic OrcaSlicer takes supports but doesn't orient; PrusaSlicer, Cura and Slic3r take neither here. Counterpart wrote Bambu Studio's behaviour into its own design prompt; it now comes from the MCP that knows its slicer. Checked with the server's prompt tests.BAMBU_NETWORK_BRIDGE_IMAGEruns FULU's Linux host in a Docker image, as in bambu-printer-mcp, withBAMBU_NETWORK_BRIDGE_DOCKER,BAMBU_NETWORK_BRIDGE_DOCKER_HOSTand an optional Colima profile that is started, never restarted, when Docker doesn't answer. It comes after an explicit bridge command and before a discovered FULU install. A Colima profile withoutBAMBU_NETWORK_BRIDGE_DOCKER_HOSTuses that profile's own socket. Concurrent calls on a cold bridge start one container. The container runs with--initand a name of its own, and is removed when the bridge stops, so stopping the server no longer leaves FULU's host running. Checked with a stand-indockerandcolima, and on a Mac against the real FULU host image in its own container: the agent started and wrote its logs and certificates to this server's folder, and no container was left afterwards. No print was sent through it.
Fixed
- FULU through this server no longer aborts on its config folder. The hand-written launcher it was pointed at mounted bambu-printer-mcp's agent folder, not this server's
~/.config/mcp-3d-printer-server/bambu-network, so the host couldn't open itslog_dir(FULU #54). WithBAMBU_NETWORK_BRIDGE_IMAGEthe server mounts its own config folder and writes each print's checked snapshot inside it (Colima shares the home folder, not/tmpor/var/folders). A config folder reached through a symlink is mounted at the path the host is given. Snapshots a killed server left behind are removed after a day. Checked with a stand-indockerandcolimarunning the fake FULU host, and against the real host image on a Mac (agent setup only; nothing printed).
[1.2.35] – 2026-11-05
Added
get_slice_settingson a 3MF returnsown_process: true whenslice_stl, given the sameslicer_typeandbambu_model(both now accepted here) and noslicer_profileor template, slices that file with its own process (a designer's Bambu Studio or Orca project). It is the same testslice_stluses, so a client can show that a designer's file prints with the designer's settings, and leave quality and strength at standard, without reading the 3MF itself. Counterpart's print sheet carried the last print's quality and strength over to a copy of a designer's 3MF, where they changed its layer height, walls or infill. Checked with a stand-in slicer.
Fixed
- 1.2.34's notes omitted one change it shipped: the preview leaves out filament-change flushing only between a material-switch
M620 S…and itsM621 S…, so setup forms such as the H2C start template'sM620 O1don't hide the part.
[1.2.34] – 2026-11-05
Added
inspect_print_filetakesinclude_preview: it then also returnspreview, two PNG pictures drawn from the exact file's G-code, with that file'sartifact_sha256. Every extruding line on the selected plate is drawn in its filament's colour at its extrusion width, including arcs (I/J or R, full circles too), without the start-up purge and prime lines or Bambu's filament-change flushing (M620 to M621). Features are read from Bambu Studio/Orca; FEATURE:and PrusaSlicer/Cura;TYPE:comments; G-code naming none is drawn whole. The first view is the top as it sits on the bed; the second is the bed side, turned over toward you so text on that face reads as it will. It never uses the plate thumbnails a sliced file carries: Bambu Studio's CLI copies a project's old plate PNGs into the sliced file unchanged, so they can show a part that isn't the one printing. Off by default, because the pictures are tens of KB of base64; it is meant for apps that show the person what will print, such as Counterpart's print sheet. On a designer's caliper card sliced on Nov 4, the preview shows the ruler ticks and vernier scale missing from the G-code, which is the defect that print had. Checked with synthetic G-code and with real Bambu Studio 2.8.2 sliced files.
[1.2.33] – 2026-11-05
Fixed
- A template's or project's process settings extract to a file named by their content, so two projects sliced at once can't overwrite each other's settings and slice with the wrong layer height, walls or infill. Checked with a concurrent extraction test.
- A 3MF that carries its own process settings (a designer's Bambu Studio or Orca project) now slices with them on the Bambu-compatible CLI route:
slice_stltakes its layer height, walls, infill and the rest of its process unless the call namesslicer_profile,template_nameortemplate_3mf_path, andprint_3mf's auto-slice does the same unless the call namesslicer_profile. A configured default profile or template used to replace them. The machine still comes frombambu_modeland the nozzle, so a project made for another printer can't bring its machine settings along. A 3MF with no process of its own, such as one fromcounterpart_make_3mf, still slices with the preset. Found when a designer's fold-and-snap caliper card (0.16 mm layers, 100% infill) was printed at the preset's values and no longer folded. Checked with a stand-in slicer. On Bambu Studio 2.8.2, that designer's file sliced through this same route (its own file astemplate_3mf_path) kept 0.16 mm, 100% infill, 2 walls and 6 top and 4 bottom layers, where the default route gave the preset's 0.2 mm and 15%. strengthstrongandmaxonly raise walls and infill: a process that already has more walls or denser infill keeps them. Strong used to write 4 walls and 25% infill as given, which lowered that caliper card's 100% infill. On PrusaSlicer and Slic3r the floor is read against the loaded config's ownperimetersandfill_density. An explicitwall_loopsorsparse_infill_densityis still written as given. Checked with a stand-in slicer only.
[1.2.32] – 2026-11-04
Added
counterpart_printer_inforeportscapabilities.slicing: whetherslice_stlcan apply supports, copies (repetitions) and auto-orient with the slicer this server uses for that printer. The Bambu-compatible CLI route takes all three, generic OrcaSlicer takes supports, and PrusaSlicer, Slic3r and Cura take none. For a Bambu printer on OrcaSlicer, that assumes the call passes the printer'sbambu_model. Clients such as Counterpart offer those choices from this instead of knowing which slicers accept what. Same field as bambu-printer-mcp 1.1.58. Checked with mocked transports only.
Changed
slice_stlwithrepetitionsabove 1 on a slicer that can't make copies (anything but the Bambu-compatible CLI route) now says so and slices nothing; it used to slice one copy without a word. Checked with stand-in slicers only.
[1.2.31] – 2026-11-04
Added
- A printer refusal on
print_3mfcarries a stablecodein its structured error:printer-command-rejectedwhen the printer refuses the print command itself (Bambu HMS 0500-0500-0001-0007, MQTT command verification; the file is on the printer, nothing is printing), andprinter-not-readywhen the printer isn't in a state that can start a print. The message and suggestion are unchanged. Clients such as Counterpart can act on the code instead of matching the wording, which changes with printers and firmware. Checked with mocked MQTT only. Same change as bambu-printer-mcp 1.1.57.
[1.2.30] – 2026-11-04
Added
slice_stlandslice_with_templatetakequality(draft,standard,fine) andstrength(standard,strong,max). The server turns them into the slicer's own settings: Draft and Fine set the layer height for the nozzle in use (0.28 and 0.12 mm on a 0.4 mm nozzle, scaled with it), Strong and Max set walls and infill (4 walls at 25%, 6 at 40%), and Standard leaves the resolved preset alone. An explicitlayer_height,wall_loopsorsparse_infill_densitystill wins. Clients such as Counterpart can now send the person's choice instead of carrying slicer numbers. Checked with stand-in slicers only. For PrusaSlicer, Slic3r and generic OrcaSlicer the layer height scales withnozzle_diameter(orNOZZLE_DIAMETER), which must match the profile's nozzle; Cura takes only Standard. Same change as bambu-printer-mcp 1.1.56.
[1.2.29] – 2026-11-04
Changed
- With no method given, a FULU print over Bambu Cloud goes the way Bambu Studio sends it to a cloud-bound printer it can reach on the LAN (
PrintJob.cpp):start_local_print_with_record, which uploads to the printer over the LAN and records the task in the account, in the account's cloud session. When that fails before the print command (the plug-in's-2010to-2140preparation results, other than a missing or oversized file), the same checked job goes once throughstart_print, with the printer checked again first. Any other failure may have reached the printer and is not sent again. A printer that reports no storage goes straight tostart_print, as in Studio. Same change as bambu-printer-mcp 1.1.55. On a P1S with firmware 01.10.00.00,start_printalone returns-3120, HTTP 403 "internal blocking", every time. Errors name-2120,-2130and-3120. Checked with the stand-in host and intercepted transports only; not yet on a printer.
[1.2.28] – 2026-11-04
Added
slice_stltakesenable_support,support_type(normal(auto),tree(auto),normal(manual),tree(manual)) andsupport_threshold_angle, written over the selected process profile likelayer_heightandwall_loops. Bambu Studio and OrcaSlicer only; PrusaSlicer and Cura refuse them. Tested with the fake Bambu Studio CLI install; bambu-printer-mcp 1.1.54 checks the same keys against the installed Bambu Studio 02.08.02.61. No printer was involved.
[1.2.27] – 2026-11-04
Added
- Every tool now carries the four MCP tool annotations (
readOnlyHint,destructiveHint,idempotentHint,openWorldHint) from one table,src/tool-annotations.ts, so clients can tell reads from actions without parsing descriptions. Before, 7 of 45 tools had partial annotations. Destructive means the tool may end or replace something that exists:cancel_print,upload_gcode(same file name),camera_snapshotwithsave_path,get_slice_settings(a same-named 3MF replaces the extracted settings file),save_template,counterpart_print_routewith a route, and the pass-through callsfulu_bambu_network_rpc,blender_mcp_callandfusion_mcp_call. Starting a print and heating are marked additive, matching the no-confirmation decision. Annotations are hints for clients; every safety check still applies. A test lists the tools over stdio and fails for any tool without all four.
Fixed
- Resume a Bambu job that the printer paused itself. A P1S paused by Pause or by a
pause_at_layersstop reportsprint_error0300_8013 ("paused by the user" / "paused by the pause command in the file"), and Resume refused it as a print error, so a paused job could only be resumed at the printer. The notice is excused only for Resume, only while the printer reports PAUSE; any other print error still refuses, and starting a job still needs no error. Ported from bambu-printer-mcp. - FULU's BambuNetwork agent now receives the client headers FULU's own GUI sends before
net.start(Bambu Studio 02.05.02.51 on Linux, with a per-install device id kept in the config folder). Bambu's cloud issues the printer-control certificate and creates print tasks for this client; without the headers the agent was an unknown client.BAMBU_NETWORK_CLIENT_NAMEandBAMBU_NETWORK_CLIENT_VERSIONoverride the name and version. Ported from bambu-printer-mcp. - Evidence: mocked Bambu MQTT/FTPS boundaries and the fake FULU host only; no printer was contacted.
[1.2.26] – 2026-11-04
Changed
- Start prints and positive heating without a server-side confirmation prompt, on every printer type. The client's own print action is the approval and the printer runs its own checks, so clients without MCP elicitation support now print and heat normally.
PRINT_REQUIRE_CONFIRMATIONandBAMBU_REQUIRE_CONFIRMATIONare removed. File inspection, hardware and material ceilings, declared materials, fresh printer state (read, rechecked before upload and again before dispatch) and Bambu identity checks are unchanged. Matches bambu-printer-mcp. resume_printasks a person only when the printer cannot hand the file back for re-reading (PrusaLink, Repetier, Creality), where the job is matched by name only. OctoPrint, Klipper and Duet (DSF) re-read the file, compare its SHA-256 and resume without a prompt.PRINT_CONFIRMATION_TIMEOUT_MSnow bounds that prompt and the Bambu printer-model prompt.- Stop treating a finished job as a bed-clearance case: a printer that reports a finished or cancelled job (Moonraker complete or cancelled, PrusaLink FINISHED or STOPPED, Creality finished, Bambu FINISH) starts the next print like an idle one. Matches bambu-printer-mcp's bed-check removal (bambu-printer-mcp #90).
- Evidence: mocked Bambu MQTT/FTPS boundaries and loopback HTTP printer APIs only; no real printer was used.
Fixed
Include the authenticated control reply module in the npm package. The route imported it but the explicit package allowlist omitted it, so a packed install exited before MCP initialization. The packed-install smoke test covers startup and discovery through all three entrypoints.
Keep authenticated FULU Pause, Resume and Stop request IDs as strings in Studio's 20000–29999 window, with a shared counter across LAN, cloud and retries that wraps inside the window. A cloud-bound P1S 01.10 rejects larger IDs with 0502400A even when their signatures are valid. Preserve reply correlation and the delivery hold; remove guidance claiming controls require Studio/Handy or Developer Mode. Automated regressions cover both transports and wraparound; hardware validation is limited to the maintainer's P1S.
An
ams_mappingobject (and the 3MF's own mapping) is ordered by project filament index, as bambu-printer-mcp orders it. Before, its tray values were sorted, so{"0": 3, "1": 0}sent tray 0 for filament 0.Bambu printers slice with Bambu Studio when
SLICER_TYPEis not set, as bambu-printer-mcp does. The previous default, FULU OrcaSlicer-bambulab, crashes on every command-line slice in its only release (v1.0.0, macOS DMG and Linux builds; fixes in FULU #56 and #57 are not released), soslice_stl, estimates and auto-slicing failed for every Bambu user without a slicer setting. FULU's Orca stays fully supported withSLICER_TYPE=orcaslicer-bambulab.A relative
TEMP_DIR(such as./temp) is resolved against the server's working directory, as bambu-printer-mcp 1.1.44 does. Bambu Studio fails every 3MF export to a relative output folder ("Project export to temp/…/…_sliced.3mf failed").Accept Bambu Studio 2.9 layer-temperature changes (
M104 M S<temperature>with an optionalTselector) in the Bambu file inspector. Preserve hardware/material ceilings, tool validation, and rejection of numeric markers, other heaters and extra parameters. Reproduced using isolated Studio 02.09.01.70 output; no physical print was run. This ports the fix prepared in bambu-printer-mcp #97.Update
basic-ftpto 6.2.5, including its 6.2.4 fix for directory listings containing inherited-property fact names. Offline listing reproduction fails with 6.2.3 and preserves the file name and size with 6.2.5; no printer was contacted.Resolve H2C first-layer temperature tables by the selected filament index and extruder variant instead of treating every variant row as a filament. Preserve unique bindings, header agreement and independent base/offset ceilings. Ports the correction reported by Steve Pritchard (sjpritchard); an unchanged Studio 2.9 H2C slice passes offline inspection after reproducing the failure.
print_3mfwith aplate_indexprints, inspects and checks pauses on that plate on every route: FULU's BambuNetwork route used to inspect and dispatch plate 1, and a pre-sliced file's requested pauses were checked against plate 1. Tested with the fake FULU host; no printer was contacted.
Added
slice_stl,slice_with_templateandprint_3mfacceptpause_at_layers, matching bambu-printer-mcp. Bambu Studio and Bambu-compatible OrcaSlicer CLIs place the printer's own pause before each requested 1-based layer (2 or greater), using a first slice to find exact heights. Existing project pauses and custom G-code are preserved. Output must contain every requested pause; already sliced files missing one are refused before dispatch. Other slicers refuse the option rather than ignoring it. Evidence: fake slicer/MCP tests only; no physical print or real slicer was run in this port.Bambu AMS inventory and tray choice, ported from bambu-printer-mcp:
get_printer_filamentsreads the AMS from the printer's MQTT report forPRINTER_TYPE=bambuinstead of refusing. The result carries bambu-printer-mcp's fields unchanged (trayswith absoluteslot,loaded,tray_type,tray_color,tray_info_idxand the resolved Bambu Studio/Orca filament profile;summary;recommended;load_filaments_all), plus counterpart/1slotsfor every loaded AMS tray and the external spool (254, and254/255on dual-nozzle printers) withsource: "printer". Optionalbambu_modelandnozzle_diameterpick model-specific profiles.counterpart_printer_inforeportsfilaments: "ams"for Bambu.print_3mfacceptsams_slots: one tray per used filament in plate order, expanded to the project-levelams_mappingfrom the plate'sfilament_idsand the G-code header, as bambu-printer-mcp does.ams_mappingalso accepts the project-level array. Tray values are checked (0–15, 128–254, and 255 on dual-nozzle printers),ams_slotsmust name exactly one tray per used filament, and the fresh-state check still compares each mapped tray's material with the file.use_ams: falsemaps every used filament to the external spool of its nozzle on the wire. Counterpart's printer handoff sends exactly these arguments.- Evidence: mocked MQTT reports and FTPS/MQTT dispatch only; no real printer was used.
Bambu
pause_printandresume_print, andcounterpart_printer_inforeportspauseandresumefor Bambu, ported from bambu-printer-mcp:- Pause and stop (
cancel_print) are never gated. Stop also retires the job's resume record. - Resume keeps bambu-printer-mcp's checked-job safety: only the job this server inspected and started, while a fresh report shows it paused under its unique name, with the fresh-state check repeated. Its bytes are re-read over FTPS (the uploaded 3MF, else the
cache/<name>_plate_<n>.gcodea P1S extracts from it) and their SHA-256 compared; a changed file retires the record. A file this server uploaded that cannot be re-read refuses the resume. Only a file Bambu's plug-in placed (FULU's BambuNetwork route) that cannot be re-read asks a person through MCP elicitation. - Every MQTT report retires a record whose job ended or was replaced, even when nobody polls.
- Checked 3MF prints are started with their unique remote name as
subtask_name, as bambu-printer-mcp does, so the printer reports back which job is paused. - Evidence: in-process FTPS/MQTT fakes only; no real printer was paused or resumed.
- Pause and stop (
Bambu connection routes, including FULU's authenticated BambuNetwork route, ported from bambu-printer-mcp, so a P1S on authorization firmware without Developer Mode prints and is controlled over the local network:
- One route decision (
resolveConnection) forprint_3mf,cancel_print,pause_printandresume_print:connection_mode(lan_mqtt_ftps, the default, orbambu_network) andconnection_type(lanorcloud;cloudwhen unset, as in bambu-printer-mcp), defaulting toBAMBU_DEFAULT_CONNECTION_MODEandBAMBU_DEFAULT_CONNECTION_TYPE. A job is controlled over the connection that printed it. bambu-printer-mcp'sbambu_native(X2D) andbambu_connectmodes are refused with a clear error; nothing is sent over another connection. print_3mfwithbambu_networkruns the same gates as the LAN path (inspection of the exact snapshot bytes, the AMS mapping, fresh LAN MQTT state before the bridge starts and again immediately before the print frame), then opens the plug-in's own session:net.start_local_printforlan,net.start_printforcloud. It sends Bambu Studio'sams_mapping,ams_mapping2andams_mapping_info, the Send dialog's calibration options as Bambu Studio resolves them, and the unique checked name as the task name. A synchronous -4030 is retried once after the certificate exchange; other non-zero results report the plug-in's code and messages. The job is recorded for a checked resume.- Stop, Pause and Resume over
bambu_networkgo through the plug-in's authenticated session, held open until the printer answers; a refusal reports the printer'serr_code, a -4/-4030 send is retried after reinstalling the certificate (three tries), and every event and send is written tocontrol-trace.login the bridge's config folder without the access code. - New
counterpart_print_routetool, same contract as bambu-printer-mcp's: reads the route (lanorcloud, with the resolved mode and type) and changes it in the running server and in the.envfile in its working directory when one exists (savedTo). - The bridge host is
BAMBU_NETWORK_BRIDGE_COMMAND(bambu-printer-mcp's name), elseFULU_BAMBU_BRIDGE_COMMAND, else the hostcheck_fulu_orca_setupdiscovers next to FULU's OrcaSlicer-bambulab. Its config folder defaults to~/.config/mcp-3d-printer-server/bambu-network(BAMBU_NETWORK_CONFIG_DIR).fulu_bambu_network_rpcstill refuses raw print methods. - Evidence: a fake FULU host process that reproduces the real v1.0.0 host and plug-in behaviour bambu-printer-mcp recorded on a P1S, plus patched printer state; no real FULU host, plug-in, printer or Bambu Cloud was used by this server.
- One route decision (
Serves design guidance for agents that design or edit models to print as MCP prompts:
fdm_design,fdm_multicolor,fdm_assemblyandfdm_after_slice, plus the resourceguidance://fdm/capability-guidancefor bridges and overhangs. The server'sinstructionspoint every client to them. The text is David Montgomery's FDM design prompt pack of 3 November 2026, unchanged; bambu-printer-mcp serves the same guidance. Tested over a real stdio MCP connection; whether an agent follows it is a model behavior, not tested here.
Documentation
- README,
docs/FULU.md,docs/SETUP.mdand.env.exampledescribe Bambu AMS inventory and tray choice, Bambu pause, resume and stop, the connection routes (BAMBU_DEFAULT_CONNECTION_MODE,BAMBU_DEFAULT_CONNECTION_TYPE,counterpart_print_route) and printing and controlling through FULU's BambuNetwork route, including its evidence limits here (a fake FULU host only).
[1.2.25] – 2026-11-02
Fixed
lay_flatrests a model on a face that is its real bottom. Before, it turned the face-normal group with the largest area to face down and moved the lowest point to Z=0, without checking that those faces were the lowest. The stove gap filler from Scan to Make (six T strips) printed upside down: its cap undersides' 23,838 mm² face down but sit 12 mm above the fin tips, so it stood on its fins.- A pose qualifies only when some face, turned down, lies on the rotated model's lowest plane, within 0.5% of its height and at most 0.2 mm. The candidate poses are the 64 largest face groups and the model's six axes, so a domed part can flip exactly.
- Among qualifying poses,
lay_flatpicks the one with the least part and support volume per mm² of bed contact. Support is the overhang more than 45° from vertical, times its height above the bed. Ties go to the larger contact, then to the face that already points down. - When no pose qualifies, the model is unchanged. The text result is still the STL path, and the new
structuredContent{path, laid_flat, message}says why. - The gap filler now comes out cap-down, fin tips 14.4 mm up. This is checked from the output vertices only. The same rule in bambu-printer-mcp was also checked by slicing with Bambu Studio 02.08.02.61 for a P1S, which gave no warning; that slice was not repeated here.
slice_stlreturns Bambu Studio's own checks on the Bambu-compatible CLI route, and OrcaSlicer's where it writes the sameresult.json. When the CLI writesresult.json(Bambu Studio 02.08.02.61 writes it on macOS on success too),structuredContent.slicer_resultcarries it parsed and unchanged:error_string,return_codeand eachsliced_plates[].warning_message. Before, the run's output directory was deleted withresult.jsonin it, and warnings such as "It seems object … has floating cantilever. Please re-orient the object or enable support generation." were lost.- The text result stays the sliced file's path.
- A failed slice is an error result whose text starts with Studio's
error_string(unless it reports success), then each plate'swarning_message, then the exit code, slicer output and suggestion, with noError:prefix. ItsstructuredContentcarriesslicer_resultbeside the existingslicerdetails. - A
result.jsonreporting a nonzeroreturn_codefails the slice even when the CLI exits 0. - The G-code slicers (PrusaSlicer, Cura, Slic3r, generic OrcaSlicer without a Bambu preset) write no
result.jsonand returnstructuredContent{path}only. - Tested with real
result.jsonfiles from Bambu Studio 02.08.02.61 slicing the Scan to Make stove gap filler for a P1S on macOS, replayed by a fake CLI. The optional installed-Studio test also checksslicer_resulton macOS; CI skips it. OrcaSlicer'sresult.jsonfollows the same libslic3r format but was not run here.
[1.2.24] – 2026-11-02
Fixed
fusion_mcp_statusreports the Fusion360MCP add-in as reachable. The pinned add-in answers a ping on its fast path with{"ok":true,"status":"pong"}, and the bridge accepted only{"pong":true}, so it reportedconnected: falsewith a running add-in. Verified against a live Fusion with the add-in at19b9f1e95192through bambu-printer-mcp's identical bridge, and with socket fixtures here.
[1.2.23] – 2026-11-02
Removed
- Remove bed-clearance checks. A finished, complete, cancelled or stopped job prints like an idle printer. There is no "remove the previous part and debris" confirmation or forced human prompt, and no "the build plate is clear" line in print confirmations. The printer detects an occupied bed itself during bed leveling. Print confirmations keep their spool and file checks, and
PRINT_REQUIRE_CONFIRMATION=0now skips every print prompt. Verified with the full suite (570 tests) using mocked printers; no physical print was run.
[1.2.22] – 2026-11-02
Fixed
camera_snapshottries both 127.0.0.1 and ::1 for alocalhostsnapshot URL. Node 18 resolveslocalhostto ::1 first with no IPv4 fallback, so a webcam that listens on IPv4 only was missed. Verified with the OctoPrint Classic Webcam test on Node 18.20.8 and the full suite on Node 22.
[1.2.21] – 2026-11-02
Added
Add the
counterpart/1tools that bambu-printer-mcp also implements, so one client can watch and control either server:counterpart_printer_info(server, printer identity and detected capabilities),counterpart_print_progress(one state, job, progress, time, layer, temperature and problem shape per firmware),camera_snapshot(bambu-printer-mcp's arguments and result pluscapturedAt),get_printer_filaments(one external slot, with Spoolman through Moonraker),pause_printandresume_print. Each declares anoutputSchemaand returnsstructuredContentplus the same JSON as text; their errors carry text only, because MCP clients validate structured content against the schema even on errors.Pause is never gated. Resume reheats and moves the printer, so it is gated like a print start. It resumes only the job this server instance inspected and started, after a fresh report that the same job is paused, and after a person confirms through MCP elicitation (unless the server sets
PRINT_REQUIRE_CONFIRMATION=0). OctoPrint, Klipper and Duet re-download the file and compare its SHA-256 with the inspected bytes before asking; PrusaLink, Repetier and Creality have no download route here, so the job is matched by name only. The printer is read again after the confirmation. Cancelling the job, or a report that it ended, retires it, so a later job that reuses the name is never resumed. A stop or heater-off request cancels a pending resume. A job started elsewhere, or before a restart, is refused. OctoPrint drops a resume sent while it is still pausing, so transitional states are reported asjob.stageand resume waits for a settled pause.upload_gcodeandstart_printresults name the remote job injobName(forstart_print, the checked copy that actually starts), matchingjob.nameincounterpart_print_progress.slice_stlandslice_with_templateacceptlayer_height,wall_loopsandsparse_infill_density, written over the selected profile: Orca and Bambu Studio process keys on the Bambu-compatible and generic OrcaSlicer paths, and--layer-height,--perimetersand--fill-densityfor PrusaSlicer and Slic3r. Cura refuses them. Profile files are never modified.get_printer_filamentsslots carryprofile, the installed slicer filament profile for the slot's material, as an absolute pathslice_stltakes asload_filaments: from Spoolman's material when Spoolman reports one, otherwise the configuredFILAMENT_PROFILE; omitted when nothing resolves. OrcaSlicer bundled, system and user presets, and PrusaSlicer/Slic3rfilament/*.inipresets, are matched exactly onfilament_type, preferring a profile whosecompatible_printerslists the printer inSLICER_PROFILE. bambu-printer-mcp's resolver did not fit: it looks up Bambu profiles by AMStray_info_idx, which other printers do not report.Behaviour change: PrusaSlicer and Slic3r now load a filament preset.
filament_profile,load_filamentsorFILAMENT_PROFILEmust be one.inipreset and is passed as a second--loadafterslicer_profile; before, it was silently ignored. A.jsonor a list is refused with instructions. Generic slicers (PrusaSlicer, Slic3r, generic OrcaSlicer) now honourload_filamentsas well as its aliasfilament_profile; before, only the Bambu CLI path readload_filaments. For generic OrcaSlicer, a filament chosen for the call replaces the|filament.jsondefault inSLICER_PROFILEinstead of becoming a second slot, and a filament preset thatinheritsinstalled presets is passed to--load-filamentswith its chain merged in (the CLI does not resolveinherits, so a bundled preset would slice without its own temperatures). A preset whose parent is not installed is passed unchanged.PRINTER_CAMERA_SNAPSHOT_URLoverrides the camera source for any printer, andREPETIER_SLUGselects the Repetier-Server printer for the new tools.Add an optional Autodesk Fusion bridge (
src/fusion-mcp-bridge.ts) to faust-machines/fusion360-mcp-server pinned at19b9f1e95192, configured withFUSION_MCP_COMMAND,FUSION_MCP_ARGS(defaulting to the pinned server in socket mode),FUSION_MCP_TIMEOUT_MSandFUSION_MCP_HOST.fusion_mcp_statusreports configuration, the Fusion process, whether the add-in answers its ping within a 2 s hard deadline (Blender's addon is not mistaken for it), and the server's tools;launch: trueopens Fusion on macOS with--env FUSION_MCP_PORT=<port>and waits up to 90 s. The add-in port defaults to 9877 (PRD §8.9) because Blender's MCP addon holds the faust default, 9876; the bridge passes it to the Fusion server too.fusion_mcp_callforwards any discovered tool with its full content and errors and never retries.fusion_mcp_new_designopens a parametric design throughexecute_code.fusion_mcp_exportwrites<name>.stl,<name>.f3dand<name>.parameters.json, verifies the STL and its units against the Fusion body, and never overwrites. Unlike the Blender bridge, the client stays connected for the life of the server. OnlyFUSION_*settings reach the Fusion process. Closing stdin now shuts the server down, so a host that disconnects without a signal does not leave it, or the Fusion child, running.
Evidence
- The pinned Fusion server started through the bridge with
uvxand listed its 93 tools; Fusion itself was not installed, so no design was built or exported live. The bridge's tests use a stdio peer that reproduces that commit's recorded--mode mockoutput. At that commit no tool works while Fusion shows its home screen without an open document (faust-machines issue #12), sofusion_mcp_new_designexplains how to open one. - OctoPrint 1.11.2 and 1.8.7 (virtual printer) and Klipper with Moonraker 1.5.0 on simulavr, with Spoolman 0.27.1: info, progress, camera snapshot, filaments, a checked upload-and-print through MCP with the confirmation answered, pause, resume (re-read bytes and its own confirmation), cancel, and a refused resume after the cancel.
jobNameequalled the reportedjob.nameon all three. These are simulators, not printers. - PrusaLink, Duet (standalone
rr_*and DSF), Repetier-Server and Creality follow their API documentation and are covered by recorded-shape mapping tests and loopback HTTP mocks only. Repetier'sdone,printTime,printedTimeCompand@pauseare not in its API manual. Creality's Moonraker ports (7125, then 4408) come from community K1 setups. Duet usesrr_modelflagsd99vinstead ofd99f, becausefomitsjob.file. - The Bambu mapping is tested offline and matches bambu-printer-mcp's encodings. This server has no Bambu camera, pause or resume path.
1.2.20 — 2026-10-30
Fixed
- Keep already-horizontal faces eligible when
lay_flatchooses the largest flat face. Thin plates now rest on their broad face at Z=0 instead of standing on an edge, including after repeated calls. When up- and down-facing areas tie exactly, as for a plate with a raised block or lettering, keep the face that already points down so a seated part is not flipped. Validate with generated STL geometry in horizontal, upside-down, edge-on, and tilted orientations and with a raised block in either face order; no printer or live Blender scene is used.
Tests
- Verify malformed HTTP JSON returns a structured 400 response while the active MCP session remains usable. Exercise loopback HTTP only; no real printer or live Blender scene is used.
1.2.19 — 2026-10-30
Fixed
- Restore Node.js 18 support removed in 1.2.18. The MCP SDK's streamable HTTP transport calls the global
crypto, which Node.js 18 lacks and@hono/node-server2.x no longer installs; the server now provides it fromnode:cryptowhen missing. The package again declares Node.js 18 or newer and CI tests 18 through 24. Fresh npm installs on Node.js 18 resolve@hono/node-server1.19.17, as they did for 1.2.18 apart from an engine warning. That version is inside GHSA-rmxm-3fg6-px4f's range, which affects onlyserveStatic; this server does not use it. Node.js 20 or newer installs the patched 2.1.5, which the repository lock keeps, so Node.js 18 CI and clones run it outside its declared Node.js 20 range. A regression starts the HTTP and SSE entrypoints without the global; the full suite and packed-install test pass on Node.js 18.20.8 and 24. Offline tests only; no printer is contacted.
1.2.18 — 2026-10-30
Changed
- Require Node.js 20 or newer. Node.js 18 reached end-of-life in April 2025, and the patched
@hono/node-serverrelies on the global Web Crypto API that Node.js 18 does not expose by default, so streamable HTTP fails there. CI now tests Node.js 20, 22 and 24.
Dependencies
- Refresh the installation lock to
@hono/node-server2.1.5 for GHSA-rmxm-3fg6-px4f usingnpm audit fixwithout forcing dependency ranges. The MCP SDK already accepts this version. The updated dependency declares Node 20 or newer; no patched 1.x release is available. This lock controls reproducible installs, not existing consumers’ locks. Validation uses offline tests and mocked transports; no printer is contacted.
1.2.17 — 2026-10-27
Fixed
- Accept the official OrcaSlicer
M620.17 T<nozzle> S<target> L-1preheat for an unused nozzle on X2D, H2D and H2D Pro. Keep the target bounded by the hardware limit and every declared material, restrict the physical nozzle to 0 or 1, and do not invent a filament/AMS position. Ported from bambu-printer-mcp 1.1.38 following ZombieLurker's H2D report. Reproduced and validated here with offline file-inspection regressions; no physical print was run.
Dependencies
- Update the MCP SDK to 1.32.2 and Axios to 1.21.0 within their supported major versions. Verify MCP startup and HTTP header/body handling alongside the adapter and package tests. Thank you to the MCP TypeScript SDK contributors and Axios contributors.
1.2.16 — 2026-10-26
Documentation
- Show the documentation site's social card directly below the README title and link it to the site.
1.2.15 — 2026-10-26
Documentation
- Link the upstream reports for FULU's Linux host: the missing
printer.cer(FULU #52), the segfault on printer-connection calls before a certificate folder is set (FULU #53), the abort on a missingcreate_agentlog folder (FULU #54), and the abort when its input closes after an agent exists (FULU #55). This server refuses the methods behind #52 and #53.fulu_bambu_network_rpccan reach #54 with a missinglog_dir, and #55 afternet.create_agentonce every request is answered; that abort is the one 1.2.14's validation saw. - Link the proposed fixes for FULU's CLI crash, FULU #56 and FULU #57. With both, a patched macOS arm64 build answers
--helpand slices a P1S cube; FULU v1.0.0 crashes on both. - Credit OrcaSlicer's fix for the 2.4.2
PartPlate::check_outsideCLI crash: OrcaSlicer #14415 by packerlschupfer, released in 2.5.0-alpha. The STL transform workaround stays while 2.4.2 is the latest stable release; FULU's CLI has the same crash until it takes that fix.
Tests
- Write the STL manipulator smoke test's outputs to a scratch folder that it removes. Every
npm testrun used to leave six output folders in the repository'stest/directory.
1.2.14 — 2026-10-25
Ported from bambu-printer-mcp 1.1.34. Its evidence came from real P1S runs and an x86-64 Linux FULU container; this repository's validation is noted in each entry.
Fixed
- Let H2D printers with stock nozzles print. Every print stopped with
Printer nozzle 0 information is unreliable, abnormal or unknownbecause the HS01 nozzles reportstat: 1permanently. Bambu Studio reads bit 0 ofstatas "information unreliable" and bits 1-2 as abnormal or unknown. Nozzles that report no identity chip (sn: "N/A") now pass bit 0, and their configured diameter and type are still compared with the job. The Bambu print prompt names them so a person confirms they match the installed hotends, and checks log them once per printer on stderr, so a headless setup still records them. Abnormal or unknown nozzles still block, and a chipped nozzle with unreliable information asks for a refresh on the printer. Reported by MorganFreeeman in bambu-printer-mcp #67 with idle and mid-print H2D firmware 01.04.00.00 reports. Validated here with that report in mocked-status regressions; no H2D hardware was available. - Say "declined or cancelled" when a person or the MCP client declines a hardware confirmation, instead of advising a client with elicitation support; clients without elicitation still get that advice. Ordinary print and heating prompts name the opt-out that applies to the printer:
PRINT_REQUIRE_CONFIRMATION=0, or alsoBAMBU_REQUIRE_CONFIRMATION=0for Bambu printers. Bed-clearance confirmations say a person must accept them. Also from bambu-printer-mcp #67; validated with mocked Bambu and generic adapters. - Stop
get_printer_statuson Bambu printers from reportingUNKNOWNwhen the printer's first MQTT push is a sparse hello (model and modules). The read returned as soon as any data had arrived; it now waits, within its existing 1.5 s bound, until the full status has merged. bambu-printer-mcp saw this twice on a P1S; validated here with a delayed-push regression. - Stop
slice_stloption combinations from crashing OrcaSlicer's CLI. OrcaSlicer 2.4.2 segfaults inPartPlate::check_outside, which needs the GUI, whenscaleorrotate_x/rotate_ymoves an object below the bed while arranging, the default for STL input. For STL input with OrcaSlicer or FULU, the server applies scale and rotations to a copy of the mesh in Orca's own order (scale, then X, then Y, then Z) and omits those flags; for 3MF input witharrange: trueit refuses that combination with an explanation.repetitionson an STL now uses Orca's--clone-objects, which cannot be combined withclone_objects. Therepetitions,arrangeandclone_objectsdescriptions now state the CLI's real limits. Bambu Studio keeps every flag. bambu-printer-mcp verified the crash and fix against OrcaSlicer 2.4.2 on Linux, including the 10 × 20 × 30 mm rotation-order check; this repository's regressions use a fake CLI that records the mesh it receives. - Report how a Bambu-compatible slicer failed: Bambu Studio and OrcaSlicer failures now name the CLI's own reason, from the
result.jsonit writes on Linux or from its exit code, next to the existing exit code or signal and output tails. Validated with a fake CLI. - Make FULU BambuNetwork bridge probes work with FULU's v1.0.0 Linux host. The host exits when its input closes, dropping requests it has not answered, so every probe and RPC call returned no responses; the server now keeps the input open until each request is answered. On Linux it passes
PJARCZAK_BAMBU_NETWORK_SOandPJARCZAK_BAMBU_SOURCE_SOinsidePJARCZAK_BAMBU_PLUGIN_DIRunless set, because the host opens them from its working directory (FULU #51). The default Linux bridge command pipes the host throughcat, because the host exits 101 on the socket stdout Node.js provides (FULU #50); probes and RPC results explain exit code 101, and the FULU guide documents a wrapper for custom commands. A handshake from a host that could not load the networking plug-in is no longer reported as ready, andfile open failednames the missing setting. A host that stops answering times out with its stderr, how many requests went unanswered and any hints, and Linux setup checks report the library paths that reach the host, including ones you set. macOS bundle notes and wrapper commands appear only for macOS, and the wrapper command only when the wrapper exists. Linux host bugs were reported with diagnosis and upstream issues by Aaron Roberts (aaroberts) in bambu-printer-mcp #68. Validated with a fake host that exits on end of input, and in the maintainer's x86-64 Linux container (QEMU emulation) against FULU's real v1.0.0 host and networking plug-in 02.05.02.58: probes were ready through the default command and the wrapper, a directly launched host returned exit 101 with its explanation, and a missing plug-in folder returned thefile open failedexplanation.net.create_agentthroughfulu_bambu_network_rpccreated an agent; the host then aborted while exiting, after answering. No printer was contacted. bambu-printer-mcp's bridge LAN printing, certificate,-4030and job-name changes do not apply: this server refuses raw bridge print and printer-connection methods and prints over its direct MQTT/FTPS path.
Documentation
- Add the FULU guide's Linux host setup and an "Upstream bugs and workarounds" table naming FULU #50 and #51, the FULU runtime's missing
printer.cer, the FULU v1.0.0 CLI crash, the OrcaSlicer 2.4.2check_outsidecrash (related to the closed OrcaSlicer #13328), and the Bambu plug-in's-4030design, with what this server does about each.
Dependencies
- Move the direct
zoddependency to 4.6.7 for GHSA-mrhx-c7xc-m3w5, memory exhaustion when validating oversized constrained collections; every zod 3 release is affected. The MCP SDK and zod-to-json-schema both accept zod 4, and this server does not import zod itself. Update body-parser to 2.4.0 (GHSA-27r3-jxmh-p828), fast-uri to 3.1.9, follow-redirects to 1.16.2, hono to 4.13.14 and ip-address to 10.7.5 for their new advisories.npm auditnow reports no vulnerabilities. The documentation site's VitePress development server still pulls vite 6.4.3 and esbuild with advisories that have no VitePress 1.x fix; they affect onlyvitepress dev, not the published static site.
1.2.13 — 2026-10-20
Dependencies
- Refresh the reproducible installation/test lock from MQTT.js 5.10.4 to 5.16.1, including its fix for reconnecting when the previous stream is already destroyed. Keep bambu-node pinned at 3.22.21 and preserve the server's checked MQTT wire format and rejection guard. Thank you to Henk Kraal (hkraal) and the MQTT.js maintainers.
- Update the documentation build's source-map-js to 1.2.2 for GHSA-68fv-2mgg-jv7q, which addresses indexed source-map offsets blocking the event loop. Thank you to 7rulnik. Refresh compatible Node 18 typings and MQTT's required transitive packages.
The root lock controls npm ci, including CI and reproducible local installs; npm does not ship that lock to consumers. Existing parent projects can retain older transitive MQTT versions and must refresh their own locks. This is not a new published MQTT minimum or a claim that every advisory is resolved. Remaining nodemon/chokidar/braces and VitePress/Vite/esbuild development-server advisories have no compatible automatic fix; no major upgrade or downgrade is forced. Printer safety behavior is unchanged and no physical printer operation is performed.
1.2.12 — 2026-10-13
Fixed
- Correct fresh H2C (
31B) and H2D Pro (239) returned-serial identity without trusting configured identity or suppressing conflicts. Accept a cloud print-job identifier inmodel_idonly when another recognized observed model or returned serial identifies the printer; unknown actual model fields still reject. Port reports from Adam (@adamkaplan, fork #47) and JaviOFC (fork #36). - Accept Bambu Studio 02.08 P2S per-variant nozzle tables alongside the selected plate header, and the exact P2S
M145 P0/P1airduct forms. Preserve selected extruder/variant conflicts and independent thermal checks. Port Izzy Mansurov's (@sapoepsilon) code and regressions from fork #33, including the subsequent selection-validation corrections. - Accept the official H2C startup forms only inside its single bounded executable startup block, with independent base/derived nozzle and bed checks and declared filament positions. Keep configuration
layer_change_gcodekeys from ending startup; actual layer markers and extrusion still close it. Reject uncheckedG383 Utargets outside the allowance. Thanks to Adam for fork #48 and the exact vendor template evidence. - Accept the official X2D bare material-switch
Bflag and exactM620.22 I<declared filament> P1runout-purge form while rejecting unsupported variants and preserving heater ceilings. Thanks to Travis Cashman (@travismcashan) for fork #44. These are file-inspection changes; no native X2D helper is added to this server.
Dependencies
- Update basic-ftp to 6.2.3 for GHSA-r4jh-29pc-gfqr: rejected control-character passwords/resume paths no longer cause an uncaught exception or leave the client unusable, and rejected PASS errors omit the password. Keep bambu-node pinned and preserve the parent's direct MQTT wire-shape and rejection guard.
Validation uses mocked transports, the pinned official H2C template, unsafe-file mutations, and clean package installations. No physical printer operation is performed or claimed.
1.2.11 — 2026-10-06
This release also includes the safety, slicing, Blender, and documentation changes prepared as 1.2.10 below. Version 1.2.10 was not published to npm.
Fixed
- Send Moonraker's configured
API_KEYasX-Api-Keyon every request, including multipart uploads and remote-file inspection downloads. Thanks to Jack Manning (@EastArctica) for #30 and Klipper 0.13.0 authentication evidence. Loopback tests cover authenticated and trusted-client configurations; no maintainer physical print was run. - Correct fresh Bambu A1/A1 mini serial identity (
039/030) and accept the official A1/A1 miniM109 Hwait parameter without weakening independently checked S/R temperature targets. Port the fork's fixes reported by @Steavie (#39) and implemented by @nitpreet22 (#41). Covered by mocked identity and file-inspection regressions. - Keep model parsing, slicing, and STL diagnostics on stderr so they cannot corrupt stdio MCP messages, following @travismcashan's report in the fork's #44. Subprocess regressions check the compiled parser and slicer.
- Make Bambu file metadata lookup read-only through the shared FTPS client; remove the obsolete
bambu-jsdependency that created directories during reads.
Dependencies and interoperability
- Update the MCP SDK to 1.32.1, basic-ftp to 6.2.2, JSZip to 3.10.2, dotenv within version 16, and proxy-addr to its patched release. The production npm audit reports no vulnerabilities; unresolved nodemon watcher advisories are development-only and remain deferred rather than forcing an unsafe downgrade.
- Verify discovery, invocation, and STL export with upstream mcp-for-blender 2.1.9 and the former blender-mcp 2.0.0 package in isolated Blender 5.0.1. The exported fixture has 12 triangles and measures 40 × 20 × 10 mm. This verifies application interoperability, not a user's live scene or a print.
Discovery
- Add the official MCP Registry ownership field and server metadata for the npm package. The listing documents printer backend configuration and marks API keys and Bambu LAN access codes as secrets.
1.2.10 — repository changes, not published to npm
Safety
- Port the bambu-printer-mcp print safety gate to every Bambu print and heat route (print_3mf, start_print, upload_gcode with print, process_and_print_stl, set_printer_temperature). Each route inspects a private snapshot of the exact selected plate or G-code (every S/R heater target and tool change), enforces per-model hardware and declared-material ceilings, and checks a fresh MQTT report of the printer's model, serial, nozzle, state, errors and loaded filament before, after the human confirmation and again before dispatch.
- Ask a human through MCP elicitation before every print start and positive heating command. PRINT_REQUIRE_CONFIRMATION=0 (all printers) or BAMBU_REQUIRE_CONFIRMATION=0 (Bambu only) opts out for headless clients; a printer reporting a finished job still asks. Clients without elicitation are refused with instructions.
- Validate temperatures as finite, non-negative numbers before connecting. Heater-off (0) and cancel are never gated and cancel pending checked prints.
- Start remote files only after downloading and inspecting them, then start a uniquely named checked copy (Bambu, OctoPrint, Moonraker, Duet). Repetier, Prusa and Creality refuse remote starts because no verified download route exists; upload the local G-code with print=true instead.
- Gate OctoPrint, Klipper/Moonraker, Duet, Repetier, Prusa and Creality with shared thermal checks: independent nozzle/bed/chamber ceilings (defaults 300/120/60 °C, server-only PRINTER_MAX_NOZZLE_TEMP, PRINTER_MAX_BED_TEMP, PRINTER_MAX_CHAMBER_TEMP), material ceilings, a declared material for positive nozzle heating (G-code filament_type or the new material argument), and adapter state checks that refuse printing, paused, errored, offline or unreadable printers. Klipper macro parameters that name a heater are checked; macro bodies on the printer cannot be inspected.
- Stop again when a cancel arrives while an OctoPrint or Repetier upload-and-print is still uploading, so the cancellation wins.
- Pass
nozzle_typeandbed_typethroughprocess_and_print_stlslicing. - Refuse RepRapFirmware
M144bed standby/activation, which heats to stored temperatures the job does not show. - Refuse RepRapFirmware
M568 A1/A2tool activation unless the job itself set that tool's standby/active target first; activation-only commands would heat to an uninspected printer-side value. - Fix process_and_print_stl, which only logged a temperature mismatch and kept printing and whose check missed R targets. Expected extruder_temp/bed_temp must now equal the sliced job's highest S/R target or nothing is uploaded.
- Stop print_3mf from uploading the original project when auto-slicing fails or the selected plate has no G-code.
- Behavior changes: print_3mf compares bed_type (default BED_TYPE, else textured_plate) with the sliced plate's bed metadata, so a file sliced for another plate or without bed metadata is refused until bed_type matches. Moonraker complete/cancelled, PrusaLink FINISHED/STOPPED and Bambu FINISH count as a finished job, so the first print after a previous job always asks a human to confirm the bed is clear, even with confirmation opted out. Generic print uploads need a plain filename so the started file is exactly the uploaded one.
- Refuse raw FULU bridge print methods, printer messages and unknown methods in fulu_bambu_network_rpc; allow_mutating_method now covers only agent/session setup methods.
- Publish Bambu safety commands with string sequence ids and keep bambu-node's internal parser errors (H2-series serials, PAUSE to IDLE after a cancel) from terminating the server, without patching bambu-node.
- Fix OctoPrint nozzle targets (tool0 instead of extruder) and use the DSF raw-text /machine/code and PUT /machine/file routes for Duet.
- Give people 10 minutes to answer confirmation prompts (PRINT_CONFIRMATION_TIMEOUT_MS) instead of the MCP SDK's 60-second default, and report an unanswered prompt as a timeout. Previously a slow answer was reported as missing elicitation support, which pointed users at disabling the prompt.
- Report what a Bambu printer did after a print command instead of assuming success: watch fresh reports (BAMBU_DISPATCH_CHECK_MS, default 15 s) and return
dispatch: "started"or"unconfirmed", or fail with an explanation when firmware 01.08.05+ refuses the command (HMS 0500-0500-0001-0007, needs LAN Only Mode and Developer Mode). Found on a real P1S, where the old code reported "sent successfully" while nothing printed. - List Bambu files over FTPS directly (ported from bambu-printer-mcp): the previous bambu-js listing returned empty folders on every failure, including on a healthy P1S with 286 files.
- Explain credential rejections (Bambu MQTT "Not authorized", FTPS 530, HTTP 401/403) as a changed access code or API key instead of advising a retry, and mark safety refusals as not retryable.
- Evidence: unit tests and MCP-level tests with mocked MQTT/FTPS boundaries and loopback HTTP printer APIs cover every gate. One real P1S run (firmware 01.08.05 or later, LAN Only Mode off) exercised the Bambu path: fresh MQTT status and AMS reads, the nozzle-type gate correctly refusing a job sliced for a stainless nozzle on a hardened-steel printer, human confirmation, and the checked FTPS upload. The firmware then refused the start command (HMS 0500-0500-0001-0007), so nothing printed; that finding produced the dispatch check above, whose logic is unit-tested but not yet seen against the firmware. No printer was heated. The other backends are verified against mocked APIs only.
Slicing
- Resolve BambuStudio, OrcaSlicer, and FULU OrcaSlicer-bambulab CLI profiles before slicing. The exact model/nozzle machine preset must exist in the selected installation,
inheritsandincludechains are flattened, and the model'scli_config.jsonentry is validated. A raw inherited preset such as P1S 0.4 is no longer passed to BambuStudio, which rejected it with exit 239 ("process not compatible with printer"). - Stop before running the slicer on missing presets, wrong nozzle sizes, missing parents or includes, cycles, malformed profiles, missing process or filament files, and machine/process lists in
slicer_profile. - Report slicer failures with the exit code or signal, timeout state, and stdout/stderr tails, plus slicer-specific suggestions instead of printer connectivity advice.
- Give every STL edit and slice its own output folder, so concurrent requests for same-named inputs cannot replace each other's result before it is used or printed, and write prepared slicer profiles atomically.
- Extend bases under the model (Z-up) instead of along Y;
extend_stl_baseandprocess_and_print_stlpreviously added the base to the model's side. - Require a nonempty
Metadata/plate_<n>.gcodein Bambu-compatible output. A checksum-only archive, missing output, or stale file from an earlier run is an error. - Add
nozzle_type(andBAMBU_NOZZLE_TYPE) so jobs can be sliced for the installed nozzle. Bambu machine presets assume the stock nozzle (stainless steel on P1S/P1P/A1), and the print gate compares the job with the printer's report, so a P1S with a hardened-steel nozzle could never print a CLI-sliced job. - Keep OrcaSlicer's absolute-extrusion normalization when the machine preset owns the layer-change G-code, so isolating machine settings cannot pair absolute E with the machine's
G92 E0resets. - Drop machine settings carried by process or filament files, including template 3MF project settings exported for another printer, so they cannot replace the selected preset's start G-code.
- Add
bed_type,load_filaments,load_filament_ids,filament_colours, template selection, and the Bambu CLI placement and transform options toslice_stl. Slicing acceptsp2s,h2s, andh2cwhen the installed slicer includes those presets. Generic OrcaSlicer keeps itsmachine;process|filamentpath unless the call passesbambu_model. - Add
slice_with_template,list_templates,save_template, andget_slice_settingsfor a local template registry (BAMBU_TEMPLATE_DIR). - Add
BAMBU_PROFILES_ROOT,BAMBU_SLICER_PROFILE_DIRS,BAMBU_TEMPLATE_DIR, andBAMBU_TEMPLATE_3MF_PATHconfiguration.
Blender MCP
- Add
blender_mcp_export_stl, which exports named objects from the live Blender scene to a new, verified STL. It writes world-space evaluated geometry without changing the scene, selection, or mode, checks the export receipt and triangle count, never overwrites files, reports bounding-box dimensions measured from the written file, supportsscale, and warns when geometry looks like it was modelled in metres. Blender MCP's ownexport_scenewrites GLB/FBX only, so edits made throughexecute_blender_codepreviously had no verified path to a printable STL. - Report measured bounding boxes for every verified STL, including
blender_mcp_edit_modelresults. blender_mcp_statuslists tool names and summaries by default (about 8 KB instead of 60 KB against mcp-for-blender 2.1.1) and returns full input schemas throughtool_namesorinclude_schemas.- Surface the Blender addon's own exception message when an export fails, and point configuration errors at the renamed
mcp-for-blenderpackage and the addon's GUI-only requirement. - Add
scripts/blender-live-check.mjs, an opt-in check against a real, isolated factory-settings Blender. Verified with Blender 5.0.1 and mcp-for-blender 2.1.1, together with an end-to-end phone-case refit (import, measure, refit, fit check, export, and a real BambuStudio P1S slice). No physical print was made.
Documentation
- Restructure the README around a copy-and-paste "Set up with your agent" request and "What to ask your agent" examples, move manual configuration to docs/SETUP.md, and add docs/SLICING.md, docs/FULU.md, docs/BLENDER.md, and CONTRIBUTORS.md.
- Publish a generated documentation site to GitHub Pages (https://dmontgomery40.github.io/mcp-3D-printer-server/).
- Make AGENTS.md the tracked source of truth for release, review, community triage, safety, and Blender rules.
1.2.9
- Address Bambu FTPS upload failures reported in #22 by using TLS 1.2 control and data channels with explicit host identity and verified session reuse, including the Node 22/24 wrapped-socket session regression. Physical X1C firmware confirmation remains outstanding; no printer commands were sent in testing.
- Port standard Blender MCP discovery, tool forwarding, and verified STL edit support from the Bambu fork. Preserve this server's legacy shell/stdin bridge.
- Validate binary STL edits in bounded memory and cap ASCII inputs at 4 MiB.
- Apply edit deadlines and cancellation to STL validation as well as MCP calls.
- Require the Bambu model on raw print starts and upload-with-print, matching the fork's safety checks. Keep uploads without printing available.
- Isolate server and inline-upload scratch paths to prevent filename traversal and collisions from overwriting or deleting unrelated files.
- Refresh vulnerable dependencies, pin the supported bambu-node API version, declare the TypeScript build dependency, build before npm packing, and report the actual package version during MCP initialization.
- Keep generated dist files out of Git and validate clean builds, protocols, package installation, and Docker builds in CI.