bambu-printer-mcp 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -716,6 +716,53 @@ Slice an STL or 3MF file using an external slicer and return the path to the out
716
716
 
717
717
  For printing on a Bambu printer, the recommended workflow is: slice with `bambustudio` to get a sliced 3MF, then pass that output path to `print_3mf`.
718
718
 
719
+ #### BambuStudio Slicer Options
720
+
721
+ When `slicer_type` is `bambustudio` (the default), these additional parameters are available on `slice_stl`:
722
+
723
+ | Parameter | Type | Description |
724
+ |-----------|------|-------------|
725
+ | `uptodate` | boolean | Update 3MF configs to latest BambuStudio presets |
726
+ | `repetitions` | number | Number of copies to print |
727
+ | `orient` | boolean | Auto-orient model for optimal printability |
728
+ | `arrange` | boolean | Auto-arrange objects on the build plate |
729
+ | `ensure_on_bed` | boolean | Lift floating models onto the bed |
730
+ | `clone_objects` | string | Clone counts per object, comma-separated (e.g. `"1,3,1,10"`) |
731
+ | `skip_objects` | string | Object indices to skip, comma-separated (e.g. `"3,5,10"`) |
732
+ | `load_filaments` | string | Filament profile paths, semicolon-separated |
733
+ | `load_filament_ids` | string | Filament-to-object mapping, comma-separated |
734
+ | `enable_timelapse` | boolean | Enable timelapse-aware slicing |
735
+ | `allow_mix_temp` | boolean | Allow mixed-temperature filaments on one plate |
736
+ | `scale` | number | Uniform scale factor |
737
+ | `rotate` | number | Z-axis rotation in degrees |
738
+ | `rotate_x` | number | X-axis rotation in degrees |
739
+ | `rotate_y` | number | Y-axis rotation in degrees |
740
+ | `min_save` | boolean | Produce smaller output 3MF (faster uploads) |
741
+ | `skip_modified_gcodes` | boolean | Ignore stale custom gcodes in the 3MF |
742
+ | `slice_plate` | number | Which plate to slice (0 = all plates, default: 0) |
743
+
744
+ **Example: Slice with auto-orient and 3 copies**
745
+ ```json
746
+ {
747
+ "stl_path": "/path/to/model.stl",
748
+ "bambu_model": "p1s",
749
+ "orient": true,
750
+ "arrange": true,
751
+ "repetitions": 3
752
+ }
753
+ ```
754
+
755
+ #### Smart Defaults (print_3mf auto-slice)
756
+
757
+ When `print_3mf` detects an unsliced 3MF and auto-slices it, these defaults are applied automatically:
758
+
759
+ - `uptodate: true` -- prevents stale config bugs from downloaded 3MFs
760
+ - `ensure_on_bed: true` -- safety net, lifts floating models onto the bed
761
+ - `min_save: true` -- smaller output for faster FTP uploads to the printer
762
+ - `skip_modified_gcodes: true` -- strips custom gcodes from other users' profiles
763
+
764
+ These defaults keep you safe when printing downloaded models. When calling `slice_stl` directly, you have full control over every flag.
765
+
719
766
  </details>
720
767
 
721
768
  <details>
package/dist/index.js CHANGED
@@ -333,7 +333,25 @@ class BambuPrinterMCPServer {
333
333
  },
334
334
  slicer_path: { type: "string", description: "Path to the slicer executable (default: value from env)" },
335
335
  slicer_profile: { type: "string", description: "Path to the slicer profile/config file (optional, overrides bambu_model preset)" },
336
- nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" }
336
+ nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" },
337
+ uptodate: { type: "boolean", description: "Refresh 3MF preset configs to match the latest BambuStudio version. Use when slicing downloaded or older 3MF files to prevent stale-config failures." },
338
+ repetitions: { type: "number", description: "Print N identical copies of the model. Each copy gets its own plate placement. Example: 3 prints three copies." },
339
+ orient: { type: "boolean", description: "Auto-orient the model for optimal printability (minimize supports, maximize bed adhesion). Recommended for raw STL imports that lack a pre-set orientation." },
340
+ arrange: { type: "boolean", description: "Auto-arrange all objects on the build plate with optimal spacing. Recommended when importing STLs or adding multiple objects. Set false to preserve existing plate layout." },
341
+ ensure_on_bed: { type: "boolean", description: "Detect models floating above the bed and lower them onto the build surface. Safety net for imported models with incorrect Z origins." },
342
+ clone_objects: { type: "string", description: "Duplicate specific objects on the plate. Comma-separated clone counts per object index, e.g. '1,3,1,10' clones object 0 once, object 1 three times, etc." },
343
+ skip_objects: { type: "string", description: "Skip specific objects during slicing by index. Comma-separated, e.g. '3,5,10'. Useful for multi-object 3MFs where you only want to print some parts." },
344
+ load_filaments: { type: "string", description: "Override filament profiles. Semicolon-separated paths to filament JSON configs, e.g. 'pla_basic.json;petg_cf.json'." },
345
+ load_filament_ids: { type: "string", description: "Map filaments to objects/parts. Comma-separated IDs matching load_filaments order, e.g. '1,2,3,1' assigns filament 1 to objects 0 and 3." },
346
+ enable_timelapse: { type: "boolean", description: "Insert timelapse parking moves into gcode. The toolhead parks at a fixed position each layer for camera capture. Adds ~10% print time." },
347
+ allow_mix_temp: { type: "boolean", description: "Allow filaments with different temperature requirements on the same plate. Required for multi-material prints mixing e.g. PLA and PETG." },
348
+ scale: { type: "number", description: "Uniform scale factor applied to all axes. 1.0 = original size, 2.0 = double, 0.5 = half. Applied before slicing." },
349
+ rotate: { type: "number", description: "Rotate the model around the Z-axis (vertical) by this many degrees before slicing. Positive = counterclockwise when viewed from above." },
350
+ rotate_x: { type: "number", description: "Rotate the model around the X-axis by this many degrees before slicing. Useful for reorienting prints for better layer adhesion." },
351
+ rotate_y: { type: "number", description: "Rotate the model around the Y-axis by this many degrees before slicing. Useful for reorienting prints for better layer adhesion." },
352
+ min_save: { type: "boolean", description: "Write a smaller output 3MF by omitting non-essential metadata. Reduces file size for faster FTP upload to the printer." },
353
+ skip_modified_gcodes: { type: "boolean", description: "Strip custom start/end gcodes embedded in the 3MF. Recommended for downloaded 3MFs since custom gcodes from other users' profiles may be unsafe for your printer." },
354
+ slice_plate: { type: "number", description: "Which plate index to slice. 0 = all plates (default). Use 1, 2, etc. to slice only a specific plate in multi-plate 3MF projects." }
337
355
  },
338
356
  required: ["stl_path", "bambu_model"]
339
357
  }
@@ -599,8 +617,45 @@ class BambuPrinterMCPServer {
599
617
  const nozzleDiam = String(args?.nozzle_diameter || DEFAULT_NOZZLE_DIAMETER);
600
618
  // Resolve printer preset for BambuStudio slicer
601
619
  const printerPreset = BAMBU_MODEL_PRESETS[sliceModel]?.(nozzleDiam);
620
+ const sliceBambuOptions = {};
621
+ if (args?.uptodate !== undefined)
622
+ sliceBambuOptions.uptodate = Boolean(args.uptodate);
623
+ if (args?.repetitions !== undefined)
624
+ sliceBambuOptions.repetitions = Number(args.repetitions);
625
+ if (args?.orient !== undefined)
626
+ sliceBambuOptions.orient = Boolean(args.orient);
627
+ if (args?.arrange !== undefined)
628
+ sliceBambuOptions.arrange = Boolean(args.arrange);
629
+ if (args?.ensure_on_bed !== undefined)
630
+ sliceBambuOptions.ensureOnBed = Boolean(args.ensure_on_bed);
631
+ if (args?.clone_objects !== undefined)
632
+ sliceBambuOptions.cloneObjects = String(args.clone_objects);
633
+ if (args?.skip_objects !== undefined)
634
+ sliceBambuOptions.skipObjects = String(args.skip_objects);
635
+ if (args?.load_filaments !== undefined)
636
+ sliceBambuOptions.loadFilaments = String(args.load_filaments);
637
+ if (args?.load_filament_ids !== undefined)
638
+ sliceBambuOptions.loadFilamentIds = String(args.load_filament_ids);
639
+ if (args?.enable_timelapse !== undefined)
640
+ sliceBambuOptions.enableTimelapse = Boolean(args.enable_timelapse);
641
+ if (args?.allow_mix_temp !== undefined)
642
+ sliceBambuOptions.allowMixTemp = Boolean(args.allow_mix_temp);
643
+ if (args?.scale !== undefined)
644
+ sliceBambuOptions.scale = Number(args.scale);
645
+ if (args?.rotate !== undefined)
646
+ sliceBambuOptions.rotate = Number(args.rotate);
647
+ if (args?.rotate_x !== undefined)
648
+ sliceBambuOptions.rotateX = Number(args.rotate_x);
649
+ if (args?.rotate_y !== undefined)
650
+ sliceBambuOptions.rotateY = Number(args.rotate_y);
651
+ if (args?.min_save !== undefined)
652
+ sliceBambuOptions.minSave = Boolean(args.min_save);
653
+ if (args?.skip_modified_gcodes !== undefined)
654
+ sliceBambuOptions.skipModifiedGcodes = Boolean(args.skip_modified_gcodes);
655
+ if (args?.slice_plate !== undefined)
656
+ sliceBambuOptions.slicePlate = Number(args.slice_plate);
602
657
  result = await this.stlManipulator.sliceSTL(String(args.stl_path), slicerType, slicerPath, slicerProfile || undefined, undefined, // progressCallback
603
- printerPreset);
658
+ printerPreset, sliceBambuOptions);
604
659
  break;
605
660
  }
606
661
  case "print_3mf": {
@@ -623,8 +678,14 @@ class BambuPrinterMCPServer {
623
678
  const hasGcode = Object.keys(zip.files).some(f => f.match(/Metadata\/plate_\d+\.gcode/i) || f.endsWith('.gcode'));
624
679
  if (!hasGcode) {
625
680
  console.log(`3MF has no gcode — auto-slicing with ${slicerType} for ${printModel}`);
681
+ const autoSliceOptions = {
682
+ uptodate: true,
683
+ ensureOnBed: true,
684
+ minSave: true,
685
+ skipModifiedGcodes: true,
686
+ };
626
687
  threeMFPath = await this.stlManipulator.sliceSTL(threeMFPath, slicerType, slicerPath, slicerProfile || undefined, undefined, // progressCallback
627
- printPreset);
688
+ printPreset, autoSliceOptions);
628
689
  console.log("Auto-sliced to: " + threeMFPath);
629
690
  }
630
691
  }
@@ -22,6 +22,26 @@ export type TransformationParams = {
22
22
  relative?: boolean;
23
23
  selectionBounds?: THREE.Box3;
24
24
  };
25
+ export interface BambuSliceOptions {
26
+ uptodate?: boolean;
27
+ repetitions?: number;
28
+ orient?: boolean;
29
+ arrange?: boolean;
30
+ ensureOnBed?: boolean;
31
+ cloneObjects?: string;
32
+ skipObjects?: string;
33
+ loadFilaments?: string;
34
+ loadFilamentIds?: string;
35
+ enableTimelapse?: boolean;
36
+ allowMixTemp?: boolean;
37
+ scale?: number;
38
+ rotate?: number;
39
+ rotateX?: number;
40
+ rotateY?: number;
41
+ minSave?: boolean;
42
+ skipModifiedGcodes?: boolean;
43
+ slicePlate?: number;
44
+ }
25
45
  export declare class STLManipulator extends EventEmitter {
26
46
  private tempDir;
27
47
  private activeOperations;
@@ -107,9 +127,10 @@ export declare class STLManipulator extends EventEmitter {
107
127
  * @param slicerProfile Optional path to the slicer profile/config file
108
128
  * @param progressCallback Optional callback for progress updates
109
129
  * @param printerPreset Optional BambuStudio printer preset name (e.g., "Bambu Lab P1S 0.4 nozzle")
130
+ * @param bambuOptions Optional BambuStudio-specific CLI flags
110
131
  * @returns Path to the generated G-code or sliced 3MF file
111
132
  */
112
- sliceSTL(stlFilePath: string, slicerType: 'prusaslicer' | 'cura' | 'slic3r' | 'orcaslicer' | 'bambustudio', slicerPath: string, slicerProfile?: string, progressCallback?: ProgressCallback, printerPreset?: string): Promise<string>;
133
+ sliceSTL(stlFilePath: string, slicerType: 'prusaslicer' | 'cura' | 'slic3r' | 'orcaslicer' | 'bambustudio', slicerPath: string, slicerProfile?: string, progressCallback?: ProgressCallback, printerPreset?: string, bambuOptions?: BambuSliceOptions): Promise<string>;
113
134
  /**
114
135
  * Enhanced version of confirmTemperatures with better error handling
115
136
  * @param gcodePath Path to the G-code file
@@ -738,9 +738,10 @@ export class STLManipulator extends EventEmitter {
738
738
  * @param slicerProfile Optional path to the slicer profile/config file
739
739
  * @param progressCallback Optional callback for progress updates
740
740
  * @param printerPreset Optional BambuStudio printer preset name (e.g., "Bambu Lab P1S 0.4 nozzle")
741
+ * @param bambuOptions Optional BambuStudio-specific CLI flags
741
742
  * @returns Path to the generated G-code or sliced 3MF file
742
743
  */
743
- async sliceSTL(stlFilePath, slicerType, slicerPath, slicerProfile, progressCallback, printerPreset) {
744
+ async sliceSTL(stlFilePath, slicerType, slicerPath, slicerProfile, progressCallback, printerPreset, bambuOptions) {
744
745
  const operationId = this.generateOperationId();
745
746
  this.activeOperations.set(operationId, true);
746
747
  if (!fs.existsSync(slicerPath)) {
@@ -809,7 +810,7 @@ export class STLManipulator extends EventEmitter {
809
810
  const outputBase = path.basename(stlFilePath, is3mf ? '.3mf' : '.stl');
810
811
  const bambuOutputPath = path.join(this.tempDir, outputBase + '_sliced.3mf');
811
812
  args = [
812
- '--slice', '0', // Slice all plates
813
+ '--slice', String(bambuOptions?.slicePlate ?? 0),
813
814
  '--export-3mf', bambuOutputPath,
814
815
  ];
815
816
  if (slicerProfile) {
@@ -825,6 +826,41 @@ export class STLManipulator extends EventEmitter {
825
826
  fs.writeFileSync(presetJson, JSON.stringify({ printer_settings_id: printerPreset }));
826
827
  args.push('--load-settings', presetJson);
827
828
  }
829
+ // BambuSliceOptions flags
830
+ if (bambuOptions?.uptodate)
831
+ args.push('--uptodate');
832
+ if (bambuOptions?.ensureOnBed)
833
+ args.push('--ensure-on-bed');
834
+ if (bambuOptions?.enableTimelapse)
835
+ args.push('--enable-timelapse');
836
+ if (bambuOptions?.allowMixTemp)
837
+ args.push('--allow-mix-temp');
838
+ if (bambuOptions?.minSave)
839
+ args.push('--min-save');
840
+ if (bambuOptions?.skipModifiedGcodes)
841
+ args.push('--skip-modified-gcodes');
842
+ if (bambuOptions?.orient !== undefined)
843
+ args.push('--orient', bambuOptions.orient ? '1' : '0');
844
+ if (bambuOptions?.arrange !== undefined)
845
+ args.push('--arrange', bambuOptions.arrange ? '1' : '0');
846
+ if (bambuOptions?.repetitions !== undefined)
847
+ args.push('--repetitions', String(bambuOptions.repetitions));
848
+ if (bambuOptions?.scale !== undefined)
849
+ args.push('--scale', String(bambuOptions.scale));
850
+ if (bambuOptions?.rotate !== undefined)
851
+ args.push('--rotate', String(bambuOptions.rotate));
852
+ if (bambuOptions?.rotateX !== undefined)
853
+ args.push('--rotate-x', String(bambuOptions.rotateX));
854
+ if (bambuOptions?.rotateY !== undefined)
855
+ args.push('--rotate-y', String(bambuOptions.rotateY));
856
+ if (bambuOptions?.cloneObjects)
857
+ args.push('--clone-objects', bambuOptions.cloneObjects);
858
+ if (bambuOptions?.skipObjects)
859
+ args.push('--skip-objects', bambuOptions.skipObjects);
860
+ if (bambuOptions?.loadFilaments)
861
+ args.push('--load-filaments', bambuOptions.loadFilaments);
862
+ if (bambuOptions?.loadFilamentIds)
863
+ args.push('--load-filament-ids', bambuOptions.loadFilamentIds);
828
864
  args.push(stlFilePath);
829
865
  // Override outputFilePath for bambustudio since it produces 3MF, not gcode
830
866
  outputFilePath = bambuOutputPath;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bambu-printer-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server for Bambu Lab 3D printers with STL manipulation, slicing, and print management",
5
5
  "main": "dist/index.js",
6
6
  "repository": "https://github.com/DMontgomery40/bambu-printer-mcp",
package/src/index.ts CHANGED
@@ -16,7 +16,7 @@ import fs from "fs";
16
16
  import path from "path";
17
17
  import { createServer as createHttpServer, type IncomingMessage, type Server as HttpServer, type ServerResponse } from "node:http";
18
18
  import { randomUUID } from "node:crypto";
19
- import { STLManipulator } from "./stl/stl-manipulator.js";
19
+ import { STLManipulator, type BambuSliceOptions } from "./stl/stl-manipulator.js";
20
20
  import { parse3MF } from './3mf_parser.js';
21
21
  import { BambuImplementation } from "./printers/bambu.js";
22
22
 
@@ -405,7 +405,25 @@ class BambuPrinterMCPServer {
405
405
  },
406
406
  slicer_path: { type: "string", description: "Path to the slicer executable (default: value from env)" },
407
407
  slicer_profile: { type: "string", description: "Path to the slicer profile/config file (optional, overrides bambu_model preset)" },
408
- nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" }
408
+ nozzle_diameter: { type: "string", description: "Nozzle diameter in mm (default: 0.4)" },
409
+ uptodate: { type: "boolean", description: "Refresh 3MF preset configs to match the latest BambuStudio version. Use when slicing downloaded or older 3MF files to prevent stale-config failures." },
410
+ repetitions: { type: "number", description: "Print N identical copies of the model. Each copy gets its own plate placement. Example: 3 prints three copies." },
411
+ orient: { type: "boolean", description: "Auto-orient the model for optimal printability (minimize supports, maximize bed adhesion). Recommended for raw STL imports that lack a pre-set orientation." },
412
+ arrange: { type: "boolean", description: "Auto-arrange all objects on the build plate with optimal spacing. Recommended when importing STLs or adding multiple objects. Set false to preserve existing plate layout." },
413
+ ensure_on_bed: { type: "boolean", description: "Detect models floating above the bed and lower them onto the build surface. Safety net for imported models with incorrect Z origins." },
414
+ clone_objects: { type: "string", description: "Duplicate specific objects on the plate. Comma-separated clone counts per object index, e.g. '1,3,1,10' clones object 0 once, object 1 three times, etc." },
415
+ skip_objects: { type: "string", description: "Skip specific objects during slicing by index. Comma-separated, e.g. '3,5,10'. Useful for multi-object 3MFs where you only want to print some parts." },
416
+ load_filaments: { type: "string", description: "Override filament profiles. Semicolon-separated paths to filament JSON configs, e.g. 'pla_basic.json;petg_cf.json'." },
417
+ load_filament_ids: { type: "string", description: "Map filaments to objects/parts. Comma-separated IDs matching load_filaments order, e.g. '1,2,3,1' assigns filament 1 to objects 0 and 3." },
418
+ enable_timelapse: { type: "boolean", description: "Insert timelapse parking moves into gcode. The toolhead parks at a fixed position each layer for camera capture. Adds ~10% print time." },
419
+ allow_mix_temp: { type: "boolean", description: "Allow filaments with different temperature requirements on the same plate. Required for multi-material prints mixing e.g. PLA and PETG." },
420
+ scale: { type: "number", description: "Uniform scale factor applied to all axes. 1.0 = original size, 2.0 = double, 0.5 = half. Applied before slicing." },
421
+ rotate: { type: "number", description: "Rotate the model around the Z-axis (vertical) by this many degrees before slicing. Positive = counterclockwise when viewed from above." },
422
+ rotate_x: { type: "number", description: "Rotate the model around the X-axis by this many degrees before slicing. Useful for reorienting prints for better layer adhesion." },
423
+ rotate_y: { type: "number", description: "Rotate the model around the Y-axis by this many degrees before slicing. Useful for reorienting prints for better layer adhesion." },
424
+ min_save: { type: "boolean", description: "Write a smaller output 3MF by omitting non-essential metadata. Reduces file size for faster FTP upload to the printer." },
425
+ skip_modified_gcodes: { type: "boolean", description: "Strip custom start/end gcodes embedded in the 3MF. Recommended for downloaded 3MFs since custom gcodes from other users' profiles may be unsafe for your printer." },
426
+ slice_plate: { type: "number", description: "Which plate index to slice. 0 = all plates (default). Use 1, 2, etc. to slice only a specific plate in multi-plate 3MF projects." }
409
427
  },
410
428
  required: ["stl_path", "bambu_model"]
411
429
  }
@@ -703,11 +721,33 @@ class BambuPrinterMCPServer {
703
721
  const nozzleDiam = String(args?.nozzle_diameter || DEFAULT_NOZZLE_DIAMETER);
704
722
  // Resolve printer preset for BambuStudio slicer
705
723
  const printerPreset = BAMBU_MODEL_PRESETS[sliceModel]?.(nozzleDiam);
724
+
725
+ const sliceBambuOptions: BambuSliceOptions = {};
726
+ if (args?.uptodate !== undefined) sliceBambuOptions.uptodate = Boolean(args.uptodate);
727
+ if (args?.repetitions !== undefined) sliceBambuOptions.repetitions = Number(args.repetitions);
728
+ if (args?.orient !== undefined) sliceBambuOptions.orient = Boolean(args.orient);
729
+ if (args?.arrange !== undefined) sliceBambuOptions.arrange = Boolean(args.arrange);
730
+ if (args?.ensure_on_bed !== undefined) sliceBambuOptions.ensureOnBed = Boolean(args.ensure_on_bed);
731
+ if (args?.clone_objects !== undefined) sliceBambuOptions.cloneObjects = String(args.clone_objects);
732
+ if (args?.skip_objects !== undefined) sliceBambuOptions.skipObjects = String(args.skip_objects);
733
+ if (args?.load_filaments !== undefined) sliceBambuOptions.loadFilaments = String(args.load_filaments);
734
+ if (args?.load_filament_ids !== undefined) sliceBambuOptions.loadFilamentIds = String(args.load_filament_ids);
735
+ if (args?.enable_timelapse !== undefined) sliceBambuOptions.enableTimelapse = Boolean(args.enable_timelapse);
736
+ if (args?.allow_mix_temp !== undefined) sliceBambuOptions.allowMixTemp = Boolean(args.allow_mix_temp);
737
+ if (args?.scale !== undefined) sliceBambuOptions.scale = Number(args.scale);
738
+ if (args?.rotate !== undefined) sliceBambuOptions.rotate = Number(args.rotate);
739
+ if (args?.rotate_x !== undefined) sliceBambuOptions.rotateX = Number(args.rotate_x);
740
+ if (args?.rotate_y !== undefined) sliceBambuOptions.rotateY = Number(args.rotate_y);
741
+ if (args?.min_save !== undefined) sliceBambuOptions.minSave = Boolean(args.min_save);
742
+ if (args?.skip_modified_gcodes !== undefined) sliceBambuOptions.skipModifiedGcodes = Boolean(args.skip_modified_gcodes);
743
+ if (args?.slice_plate !== undefined) sliceBambuOptions.slicePlate = Number(args.slice_plate);
744
+
706
745
  result = await this.stlManipulator.sliceSTL(
707
746
  String(args.stl_path), slicerType, slicerPath,
708
747
  slicerProfile || undefined,
709
748
  undefined, // progressCallback
710
- printerPreset
749
+ printerPreset,
750
+ sliceBambuOptions
711
751
  );
712
752
  break;
713
753
  }
@@ -737,10 +777,17 @@ class BambuPrinterMCPServer {
737
777
  );
738
778
  if (!hasGcode) {
739
779
  console.log(`3MF has no gcode — auto-slicing with ${slicerType} for ${printModel}`);
780
+ const autoSliceOptions: BambuSliceOptions = {
781
+ uptodate: true,
782
+ ensureOnBed: true,
783
+ minSave: true,
784
+ skipModifiedGcodes: true,
785
+ };
740
786
  threeMFPath = await this.stlManipulator.sliceSTL(
741
787
  threeMFPath, slicerType, slicerPath, slicerProfile || undefined,
742
788
  undefined, // progressCallback
743
- printPreset
789
+ printPreset,
790
+ autoSliceOptions
744
791
  );
745
792
  console.log("Auto-sliced to: " + threeMFPath);
746
793
  }
@@ -40,6 +40,28 @@ export type TransformationParams = {
40
40
  selectionBounds?: THREE.Box3;
41
41
  };
42
42
 
43
+ // BambuStudio CLI flags exposed via the slice_stl tool
44
+ export interface BambuSliceOptions {
45
+ uptodate?: boolean; // --uptodate: update 3MF configs to latest presets
46
+ repetitions?: number; // --repetitions N: print N copies
47
+ orient?: boolean; // --orient 1: auto-orient for printability
48
+ arrange?: boolean; // --arrange 1: auto-arrange objects on plate
49
+ ensureOnBed?: boolean; // --ensure-on-bed: lift floating models onto bed
50
+ cloneObjects?: string; // --clone-objects "1,3,1,10": clone counts per object
51
+ skipObjects?: string; // --skip-objects "3,5,10": skip specific objects
52
+ loadFilaments?: string; // --load-filaments "f1.json;f2.json": filament profiles
53
+ loadFilamentIds?: string; // --load-filament-ids "1,2,3,1": filament-to-object mapping
54
+ enableTimelapse?: boolean; // --enable-timelapse: timelapse-aware slicing
55
+ allowMixTemp?: boolean; // --allow-mix-temp: allow mixed-temp filaments
56
+ scale?: number; // --scale factor: uniform scale
57
+ rotate?: number; // --rotate degrees: Z-axis rotation
58
+ rotateX?: number; // --rotate-x degrees
59
+ rotateY?: number; // --rotate-y degrees
60
+ minSave?: boolean; // --min-save: smaller output 3MF
61
+ skipModifiedGcodes?: boolean;// --skip-modified-gcodes: ignore stale custom gcodes
62
+ slicePlate?: number; // --slice N: which plate (default: 0 = all)
63
+ }
64
+
43
65
  export class STLManipulator extends EventEmitter {
44
66
  private tempDir: string;
45
67
  private activeOperations: Map<string, boolean> = new Map();
@@ -966,6 +988,7 @@ export class STLManipulator extends EventEmitter {
966
988
  * @param slicerProfile Optional path to the slicer profile/config file
967
989
  * @param progressCallback Optional callback for progress updates
968
990
  * @param printerPreset Optional BambuStudio printer preset name (e.g., "Bambu Lab P1S 0.4 nozzle")
991
+ * @param bambuOptions Optional BambuStudio-specific CLI flags
969
992
  * @returns Path to the generated G-code or sliced 3MF file
970
993
  */
971
994
  async sliceSTL(
@@ -974,7 +997,8 @@ export class STLManipulator extends EventEmitter {
974
997
  slicerPath: string,
975
998
  slicerProfile?: string,
976
999
  progressCallback?: ProgressCallback,
977
- printerPreset?: string
1000
+ printerPreset?: string,
1001
+ bambuOptions?: BambuSliceOptions
978
1002
  ): Promise<string> {
979
1003
  const operationId = this.generateOperationId();
980
1004
  this.activeOperations.set(operationId, true);
@@ -1051,7 +1075,7 @@ export class STLManipulator extends EventEmitter {
1051
1075
  const outputBase = path.basename(stlFilePath, is3mf ? '.3mf' : '.stl');
1052
1076
  const bambuOutputPath = path.join(this.tempDir, outputBase + '_sliced.3mf');
1053
1077
  args = [
1054
- '--slice', '0', // Slice all plates
1078
+ '--slice', String(bambuOptions?.slicePlate ?? 0),
1055
1079
  '--export-3mf', bambuOutputPath,
1056
1080
  ];
1057
1081
  if (slicerProfile) {
@@ -1068,6 +1092,26 @@ export class STLManipulator extends EventEmitter {
1068
1092
  fs.writeFileSync(presetJson, JSON.stringify({ printer_settings_id: printerPreset }));
1069
1093
  args.push('--load-settings', presetJson);
1070
1094
  }
1095
+
1096
+ // BambuSliceOptions flags
1097
+ if (bambuOptions?.uptodate) args.push('--uptodate');
1098
+ if (bambuOptions?.ensureOnBed) args.push('--ensure-on-bed');
1099
+ if (bambuOptions?.enableTimelapse) args.push('--enable-timelapse');
1100
+ if (bambuOptions?.allowMixTemp) args.push('--allow-mix-temp');
1101
+ if (bambuOptions?.minSave) args.push('--min-save');
1102
+ if (bambuOptions?.skipModifiedGcodes) args.push('--skip-modified-gcodes');
1103
+ if (bambuOptions?.orient !== undefined) args.push('--orient', bambuOptions.orient ? '1' : '0');
1104
+ if (bambuOptions?.arrange !== undefined) args.push('--arrange', bambuOptions.arrange ? '1' : '0');
1105
+ if (bambuOptions?.repetitions !== undefined) args.push('--repetitions', String(bambuOptions.repetitions));
1106
+ if (bambuOptions?.scale !== undefined) args.push('--scale', String(bambuOptions.scale));
1107
+ if (bambuOptions?.rotate !== undefined) args.push('--rotate', String(bambuOptions.rotate));
1108
+ if (bambuOptions?.rotateX !== undefined) args.push('--rotate-x', String(bambuOptions.rotateX));
1109
+ if (bambuOptions?.rotateY !== undefined) args.push('--rotate-y', String(bambuOptions.rotateY));
1110
+ if (bambuOptions?.cloneObjects) args.push('--clone-objects', bambuOptions.cloneObjects);
1111
+ if (bambuOptions?.skipObjects) args.push('--skip-objects', bambuOptions.skipObjects);
1112
+ if (bambuOptions?.loadFilaments) args.push('--load-filaments', bambuOptions.loadFilaments);
1113
+ if (bambuOptions?.loadFilamentIds) args.push('--load-filament-ids', bambuOptions.loadFilamentIds);
1114
+
1071
1115
  args.push(stlFilePath);
1072
1116
  // Override outputFilePath for bambustudio since it produces 3MF, not gcode
1073
1117
  outputFilePath = bambuOutputPath;