Skip to main content
Glama
Noosbai
by Noosbai

generate_prusaslicer_config

Generate custom PrusaSlicer configuration files (.ini) for specific print goals, materials, and printers. Create optimized profiles by specifying print intentions, materials, nozzle sizes, and custom settings.

Instructions

Génère un fichier .ini compatible PrusaSlicer à partir d'une intention ou de paramètres custom. Le fichier peut être chargé directement avec --load dans PrusaSlicer.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
printerNoNom de l'imprimanteGeneric
nozzleNoDiamètre de buse en mm
goalYesIntention d'impression
materialNoMatériauPLA
stl_pathNoChemin STL pour analyse auto
output_pathNoChemin de sortie pour le .ini (sinon fichier temporaire)
custom_settingsNoParamètres custom PrusaSlicer à overrider (ex: {"layer_height": 0.15})

Implementation Reference

  • Main handler function for generate_prusaslicer_config tool. Parses STL (if provided), generates profile recommendations via recommendProfile(), converts to INI settings, applies custom overrides, writes the config file, and returns formatted output with usage instructions.
    async ({ printer, nozzle, goal, material, stl_path, output_path, custom_settings }) => {
      try {
        // Mesh analysis if STL provided
        let meshAnalysis: MeshAnalysis | undefined;
        if (stl_path && existsSync(stl_path)) {
          const stl = await parseStl(stl_path);
          meshAnalysis = analyzeMesh(stl);
        }
    
        // Generate recommendation
        const profile = recommendProfile(printer, nozzle, goal, material, meshAnalysis);
        const settings = profileToIniSettings(profile);
    
        // Apply custom overrides (preserve MVS if not explicitly set)
        if (custom_settings) {
          const hasMvs = "max_volumetric_speed" in custom_settings ||
                         "filament_max_volumetric_speed" in custom_settings;
          for (const [key, value] of Object.entries(custom_settings)) {
            settings[key] = value;
          }
          // Ensure MVS is always present — critical for PrusaSlicer speed limiting
          if (!hasMvs && !settings["filament_max_volumetric_speed"]) {
            settings["filament_max_volumetric_speed"] = settings["max_volumetric_speed"] ?? 15;
          }
        }
    
        // Determine output path
        const finalPath =
          output_path ??
          join(tmpdir(), `prusaslicer-${profile.goal}-${Date.now()}.ini`);
    
        await writeRawIniFile(settings, finalPath);
    
        // Also return the ini content as text for immediate use
        const iniContent = serializeIni(settings);
    
        const lines = [
          `## Config PrusaSlicer générée`,
          `**Fichier** : ${finalPath}`,
          `**Objectif** : ${profile.goal} | **Matériau** : ${profile.material} | **Buse** : ${profile.nozzle}mm`,
          "",
          "```ini",
          iniContent.trim(),
          "```",
          "",
          `Usage PrusaSlicer CLI :`,
          "```",
          `prusa-slicer-console.exe --load "${finalPath}" --export-gcode model.stl`,
          "```",
        ];
    
        return {
          content: [{ type: "text" as const, text: lines.join("\n") }],
        };
      } catch (error) {
        return {
          isError: true,
          content: [{
            type: "text" as const,
            text: `Erreur de génération : ${error instanceof Error ? error.message : String(error)}`,
          }],
        };
      }
    },
  • Tool registration via registerGenerateConfig(). Defines the tool name 'generate_prusaslicer_config', metadata (title, description), Zod input schema (printer, nozzle, goal, material, stl_path, output_path, custom_settings), and the async handler function.
    export function registerGenerateConfig(server: McpServer) {
      server.registerTool(
        "generate_prusaslicer_config",
        {
          title: "Générer un fichier config PrusaSlicer",
          description:
            "Génère un fichier .ini compatible PrusaSlicer à partir d'une intention ou de paramètres custom. " +
            "Le fichier peut être chargé directement avec --load dans PrusaSlicer.",
          inputSchema: {
            printer: z.string().default("Generic").describe("Nom de l'imprimante"),
            nozzle: z.number().default(0.4).describe("Diamètre de buse en mm"),
            goal: z.string().describe("Intention d'impression"),
            material: z.string().default("PLA").describe("Matériau"),
            stl_path: z.string().optional().describe("Chemin STL pour analyse auto"),
            output_path: z.string().optional().describe("Chemin de sortie pour le .ini (sinon fichier temporaire)"),
            custom_settings: z
              .record(z.string(), z.union([z.string(), z.number()]))
              .optional()
              .describe("Paramètres custom PrusaSlicer à overrider (ex: {\"layer_height\": 0.15})"),
          },
        },
        async ({ printer, nozzle, goal, material, stl_path, output_path, custom_settings }) => {
          try {
            // Mesh analysis if STL provided
            let meshAnalysis: MeshAnalysis | undefined;
            if (stl_path && existsSync(stl_path)) {
              const stl = await parseStl(stl_path);
              meshAnalysis = analyzeMesh(stl);
            }
    
            // Generate recommendation
            const profile = recommendProfile(printer, nozzle, goal, material, meshAnalysis);
            const settings = profileToIniSettings(profile);
    
            // Apply custom overrides (preserve MVS if not explicitly set)
            if (custom_settings) {
              const hasMvs = "max_volumetric_speed" in custom_settings ||
                             "filament_max_volumetric_speed" in custom_settings;
              for (const [key, value] of Object.entries(custom_settings)) {
                settings[key] = value;
              }
              // Ensure MVS is always present — critical for PrusaSlicer speed limiting
              if (!hasMvs && !settings["filament_max_volumetric_speed"]) {
                settings["filament_max_volumetric_speed"] = settings["max_volumetric_speed"] ?? 15;
              }
            }
    
            // Determine output path
            const finalPath =
              output_path ??
              join(tmpdir(), `prusaslicer-${profile.goal}-${Date.now()}.ini`);
    
            await writeRawIniFile(settings, finalPath);
    
            // Also return the ini content as text for immediate use
            const iniContent = serializeIni(settings);
    
            const lines = [
              `## Config PrusaSlicer générée`,
              `**Fichier** : ${finalPath}`,
              `**Objectif** : ${profile.goal} | **Matériau** : ${profile.material} | **Buse** : ${profile.nozzle}mm`,
              "",
              "```ini",
              iniContent.trim(),
              "```",
              "",
              `Usage PrusaSlicer CLI :`,
              "```",
              `prusa-slicer-console.exe --load "${finalPath}" --export-gcode model.stl`,
              "```",
            ];
    
            return {
              content: [{ type: "text" as const, text: lines.join("\n") }],
            };
          } catch (error) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: `Erreur de génération : ${error instanceof Error ? error.message : String(error)}`,
              }],
            };
          }
        },
      );
    }
  • Zod input schema validation for the tool parameters. Defines printer (string), nozzle (number), goal (string), material (string), stl_path (optional string), output_path (optional string), and custom_settings (optional record of string/number values).
    inputSchema: {
      printer: z.string().default("Generic").describe("Nom de l'imprimante"),
      nozzle: z.number().default(0.4).describe("Diamètre de buse en mm"),
      goal: z.string().describe("Intention d'impression"),
      material: z.string().default("PLA").describe("Matériau"),
      stl_path: z.string().optional().describe("Chemin STL pour analyse auto"),
      output_path: z.string().optional().describe("Chemin de sortie pour le .ini (sinon fichier temporaire)"),
      custom_settings: z
        .record(z.string(), z.union([z.string(), z.number()]))
        .optional()
        .describe("Paramètres custom PrusaSlicer à overrider (ex: {\"layer_height\": 0.15})"),
    },
  • Core recommendation engine function recommendProfile(). Takes printer, nozzle, goal, material, and optional mesh analysis to generate a RecommendedProfile with all settings including MVS calculations, nozzle adjustments, support/brim decisions, and detailed warnings based on Bible FDM rules.
    export function recommendProfile(
      printer: string,
      nozzle: number,
      goal: string,
      material: string,
      meshAnalysis?: MeshAnalysis,
      options?: { inputShaper?: boolean },
    ): RecommendedProfile {
      // Validate nozzle diameter
      if (!nozzle || nozzle <= 0 || nozzle > 3) {
        nozzle = 0.4; // safe fallback
      }
    
      // Resolve goal
      const resolvedGoal = resolveGoal(goal);
      const preset = GOALS[resolvedGoal];
    
      // Resolve material
      const mat = MATERIALS[material.toUpperCase()] ?? MATERIALS["PLA"];
    
      // Nozzle specs (Bible FDM rules)
      const nozzleSpec = getNozzleSpec(nozzle);
    
      // Input Shaper mode (Bible FDM: higher accel/speed if firmware supports it)
      const inputShaper = options?.inputShaper ?? false;
    
      // Base speeds (mm/s) — higher base if Input Shaper enabled
      const baseSpeed = inputShaper ? 80 : 60;
      const baseTravelSpeed = inputShaper ? 200 : 150;
    
      // Compute settings
      const warnings: string[] = [];
    
      // Input Shaper warning
      if (inputShaper) {
        warnings.push("Mode Input Shaper activé — vitesses et accélérations plus élevées (Bible FDM: vérifier correspondance profil ⇄ firmware)");
      }
    
      // Layer height: nozzle × ratio, clamped to [25%, 80%] of nozzle (Bible FDM rule)
      const rawLayerHeight = round2(nozzle * preset.layerRatio);
      const layerHeight = clamp(rawLayerHeight, nozzleSpec.minLayerHeight, nozzleSpec.maxLayerHeight);
    
      // Line width: PrusaSlicer default = 1.125×nozzle, or wider for speed
      const lineWidth = resolvedGoal === "speed"
        ? round2(nozzle * 1.2)
        : nozzleSpec.autoExtrusionWidth;
    
      // Print speed — compute but then check against MVS
      let printSpeed = Math.round(baseSpeed * preset.speedMultiplier);
    
      // MVS check: volumetric_flow = layer_height × line_width × speed
      // Bible: MVS is THE central parameter — caps speed automatically
      const maxVolumetricFlow = mat.maxVolumetricSpeed;
      const theoreticalFlow = layerHeight * lineWidth * printSpeed;
      let mvsLimited = false;
    
      if (theoreticalFlow > maxVolumetricFlow) {
        const cappedSpeed = Math.floor(maxVolumetricFlow / (layerHeight * lineWidth));
        warnings.push(
          `Débit volumique capé par MVS (${maxVolumetricFlow} mm³/s pour ${mat.name}) : ` +
          `${printSpeed}mm/s → ${cappedSpeed}mm/s. ` +
          `Astuce Bible FDM : réduire la hauteur de couche peut donner du "détail gratuit" sans augmenter le temps.`
        );
        printSpeed = cappedSpeed;
        mvsLimited = true;
      }
    
      // TPU needs slow speed (Bible: vitesse cadrée via MVS)
      if (mat.name === "TPU") {
        printSpeed = Math.min(printSpeed, 25);
        if (!mvsLimited) {
          warnings.push("TPU: vitesse limitée à 25mm/s max. Direct drive recommandé.");
        }
      }
    
      const travelSpeed = Math.round(baseTravelSpeed * Math.min(preset.speedMultiplier, 1.5));
      const firstLayerSpeed = Math.round(printSpeed * 0.5);
    
      // Infill
      let infill = preset.infill;
      let fillPattern = preset.fillPattern;
      if (resolvedGoal === "strong" && meshAnalysis) {
        if (meshAnalysis.volume < 5000) {
          infill = 80;
          warnings.push("Pièce très petite (<5cm³) — infill augmenté à 80% pour la solidité");
        }
      }
    
      // Perimeters
      const perimeters = preset.perimeters;
    
      // Supports — based on mesh analysis
      let supportMaterial = false;
      let supportStyle = "grid";
      // Bible: Top contact Z distance = 50-75% of layer height
      const supportContactDistance = round2(layerHeight * 0.6);
      if (meshAnalysis && meshAnalysis.overhangPercent > 5) {
        supportMaterial = true;
        supportStyle = meshAnalysis.overhangPercent > 20 ? "snug" : "grid";
        warnings.push(
          `${meshAnalysis.overhangPercent.toFixed(1)}% de faces en overhang détectées — supports activés`
        );
      }
    
      // Brim — if small footprint or ABS/ASA/Nylon/PC or tall piece
      let brimWidth = 0;
      const needsBrim =
        mat.requiresEnclosure ||
        (meshAnalysis && meshAnalysis.boundingBox.size.z > 3 * Math.max(
          meshAnalysis.boundingBox.size.x,
          meshAnalysis.boundingBox.size.y
        ));
    
      if (needsBrim) {
        brimWidth = 5;
        warnings.push("Brim activé (5mm) — matériau sujet au warping ou pièce haute/étroite");
      }
    
      // Acceleration
      let acceleration = 1000;
      if (resolvedGoal === "speed") acceleration = 2500;
      if (resolvedGoal === "quality") acceleration = 500;
      if (mat.name === "TPU") acceleration = 500;
    
      // Cooling (Bible: detailed per material)
      const fanSpeed = mat.fanSpeed;
      const minFanSpeed = mat.minFanSpeed;
      const bridgeFanSpeed = mat.bridgeFanSpeed ?? 100;
      let minLayerTime = 10;
      if (resolvedGoal === "quality") {
        minLayerTime = 15;
      }
    
      // Nozzle temp adjustment for large nozzles (Bible: +10-20°C for 0.6mm+ nozzle to increase flow)
      let nozzleTemp = mat.nozzleTemp;
      let firstLayerNozzleTemp = mat.firstLayerNozzleTemp;
      if (nozzle >= 0.6 && resolvedGoal === "speed") {
        nozzleTemp += 15;
        firstLayerNozzleTemp += 10;
        warnings.push(
          `Buse ≥0.6mm en mode speed : temp buse +15°C (${nozzleTemp}°C) pour suivre le débit volumique (Bible FDM : PLA imprimable 10-20°C plus chaud avec buse 0.6mm)`
        );
      } else if (resolvedGoal === "speed") {
        nozzleTemp += 10;
        firstLayerNozzleTemp += 5;
        warnings.push("Mode speed : température buse +10°C pour suivre le débit");
      }
    
      // Bed temp
      const bedTemp = mat.bedTemp;
      const firstLayerBedTemp = mat.firstLayerBedTemp ?? bedTemp;
    
      // Drying warnings for hygroscopic materials (Bible FDM)
      const DRYING_INFO: Record<string, string> = {
        NYLON: "Nylon : séchage obligatoire 12h@80°C. Hygroscopique — stocker sous vide avec dessiccant.",
        PC: "PC : séchage recommandé 8h@80°C. Sensible à l'humidité.",
        TPU: "TPU : séchage recommandé 4h@50°C. Absorbe l'humidité rapidement.",
        PETG: "PETG : séchage recommandé 4-6h@65°C si stringing/bulles persistants. Modérément hygroscopique.",
        PVA: "PVA : séchage obligatoire 8h@45°C. Extrêmement hygroscopique — utiliser immédiatement après séchage.",
        BVOH: "BVOH : séchage obligatoire 6h@50°C. Très hygroscopique.",
      };
      const dryInfo = DRYING_INFO[mat.name.toUpperCase()];
      if (dryInfo) {
        warnings.push(`Bible FDM — ${dryInfo}`);
      }
    
      // Enclosure warnings (Bible FDM)
      if (mat.requiresEnclosure) {
        warnings.push(`${mat.name}: enceinte fermée obligatoire — ${mat.notes}`);
      }
    
      // Recommended surface (Bible FDM)
      if (mat.recommendedSurface) {
        warnings.push(`Surface plateau recommandée : ${mat.recommendedSurface}`);
      }
    
      // Extrusion multiplier (Bible: calibration fine du débit réel, default 1.0)
      const extrusionMultiplier = 1.0;
    
      // Build the recommendation
      const settings: RecommendedProfile["settings"] = {
        layer_height: {
          value: layerHeight,
          reason: `Buse ${nozzle}mm — plage utilisable ${nozzleSpec.minLayerHeight}-${nozzleSpec.maxLayerHeight}mm (Bible FDM: 25%-80% du diamètre buse). ` +
            `Ratio ${preset.layerRatio} → ${rawLayerHeight}mm (${preset.description})`,
        },
        line_width: {
          value: lineWidth,
          reason: `PrusaSlicer auto = ${nozzleSpec.autoExtrusionWidth}mm (1.125×buse). ` +
            `${resolvedGoal === "speed" ? "Mode speed: 1.2×buse pour débit max." : "Valeur standard PrusaSlicer."}`,
        },
        perimeters: {
          value: perimeters,
          reason: resolvedGoal === "strong"
            ? "5 parois pour résistance mécanique maximale"
            : resolvedGoal === "vase"
              ? "1 paroi — mode vase spirale"
              : `${perimeters} parois — ${preset.description.toLowerCase()}`,
        },
        infill_density: {
          value: infill,
          reason: resolvedGoal === "strong"
            ? `${infill}% — haute densité pour résistance`
            : resolvedGoal === "vase"
              ? "0% — mode vase, pas de remplissage"
              : `${infill}% — suffisant pour ${preset.description.toLowerCase()}`,
        },
        fill_pattern: {
          value: fillPattern,
          reason: fillPattern === "gyroid"
            ? "Gyroid — isotrope, bonne résistance dans toutes les directions, beau rendu"
            : fillPattern === "cubic"
              ? "Cubic — résistance 3D optimale pour pièces structurelles"
              : "Grid — simple et rapide",
        },
        nozzle_temperature: {
          value: nozzleTemp,
          reason: `${mat.name} officiel Prusa : ${mat.nozzleTemp}°C${nozzleTemp !== mat.nozzleTemp ? ` (ajusté +${nozzleTemp - mat.nozzleTemp}°C pour débit)` : ""}`,
        },
        first_layer_nozzle_temperature: {
          value: firstLayerNozzleTemp,
          reason: `Première couche ${firstLayerNozzleTemp}°C — légèrement plus chaude pour meilleure adhésion (Bible FDM)`,
        },
        bed_temperature: {
          value: bedTemp,
          reason: `${mat.name} — ${bedTemp}°C (valeur Prusa officielle)`,
        },
        first_layer_bed_temperature: {
          value: firstLayerBedTemp,
          reason: firstLayerBedTemp !== bedTemp
            ? `Première couche : ${firstLayerBedTemp}°C (5°C+ pour adhésion initiale — Bible FDM)`
            : `${firstLayerBedTemp}°C — même que le reste`,
        },
        print_speed: {
          value: printSpeed,
          reason: mvsLimited
            ? `Limité par MVS ${maxVolumetricFlow} mm³/s (${mat.name}). Formule: MVS = layer_height × extrusion_width × speed`
            : `Base ${baseSpeed}mm/s × ${preset.speedMultiplier} (${resolvedGoal})${mat.name === "TPU" ? " — limité pour TPU" : ""}`,
        },
        travel_speed: {
          value: travelSpeed,
          reason: `Déplacement rapide — ${travelSpeed}mm/s`,
        },
        first_layer_speed: {
          value: firstLayerSpeed,
          reason: `50% de la vitesse d'impression — adhésion première couche (Bible FDM : 1ère couche dépend de calibration Z et temp)`,
        },
        support_material: {
          value: supportMaterial,
          reason: meshAnalysis
            ? supportMaterial
              ? `Overhangs détectés (${meshAnalysis.overhangPercent.toFixed(1)}%) — supports nécessaires`
              : `Pas d'overhangs significatifs (${meshAnalysis.overhangPercent.toFixed(1)}%)`
            : "Pas d'analyse mesh disponible — à évaluer visuellement",
        },
        support_material_style: {
          value: supportStyle,
          reason: supportStyle === "snug"
            ? "Beaucoup d'overhangs — support snug pour meilleur contact"
            : "Support grid — standard, facile à retirer",
        },
        support_material_contact_distance: {
          value: supportContactDistance,
          reason: `${supportContactDistance}mm — ~60% de la hauteur de couche (Bible FDM : 50-75% recommandé pour bon retrait)`,
        },
        brim_width: {
          value: brimWidth,
          reason: brimWidth > 0
            ? "Brim pour améliorer l'adhésion et réduire le warping"
            : "Pas de brim nécessaire — bonne surface de contact",
        },
        fan_speed: {
          value: fanSpeed,
          reason: fanSpeed === 0
            ? `${mat.name} — ventilateur désactivé (sinon délamination/warping — Bible FDM)`
            : `${mat.name} — ventilateur à ${fanSpeed}% pour refroidissement optimal`,
        },
        min_fan_speed: {
          value: minFanSpeed,
          reason: `Minimum ${minFanSpeed}%`,
        },
        bridge_fan_speed: {
          value: bridgeFanSpeed,
          reason: `${bridgeFanSpeed}% pour les ponts — refroidissement accru nécessaire pour solidifier le pont (Bible FDM)`,
        },
        min_layer_time: {
          value: minLayerTime,
          reason: `${minLayerTime}s minimum par couche — laisse le temps au plastique de refroidir`,
        },
        retraction_length: {
          value: mat.retractionLength,
          reason: mat.name === "TPU"
            ? `${mat.retractionLength}mm — minimale pour flexible (Bible FDM: rétraction délicate TPU)`
            : mat.name === "PETG"
              ? `${mat.retractionLength}mm — Bible FDM: PETG max 0.8-1mm rétraction`
              : `${mat.retractionLength}mm — standard ${mat.name}. Bible FDM: max 2mm MK3, 3.2mm MINI (bowden).`,
        },
        retraction_speed: {
          value: mat.retractionSpeed,
          reason: `${mat.retractionSpeed}mm/s — vitesse de rétraction ${mat.name}`,
        },
        max_volumetric_speed: {
          value: maxVolumetricFlow,
          reason: `${maxVolumetricFlow} mm³/s — Bible FDM : valeur officielle ${mat.name}. ` +
            `Le MVS est LE levier central PrusaSlicer : il limite auto les vitesses quand nécessaire ` +
            `sans recalculer manuellement (Filament Settings prime sur Print Settings).`,
        },
        extrusion_multiplier: {
          value: extrusionMultiplier,
          reason: `${extrusionMultiplier} — calibration fine du débit réel. Bible FDM : calibrer EM avant d'ajuster rétraction (un mauvais EM imite stringing/blobs).`,
        },
        acceleration: {
          value: acceleration,
          reason: resolvedGoal === "speed"
            ? "2500mm/s² — accélération haute. Bible FDM : trop haut = ringing/layer shift."
            : resolvedGoal === "quality"
              ? "500mm/s² — accélération basse pour réduire ringing (vibrations)"
              : `1000mm/s² — compromis standard. Bible FDM : ajuster si layer shift ou ringing.`,
        },
      };
    
      return {
        goal: resolvedGoal,
        printer,
        nozzle,
        material: mat.name,
        settings,
        warnings,
      };
    }
  • Helper function profileToIniSettings() that converts a RecommendedProfile to PrusaSlicer .ini key-value pairs, handling all PrusaSlicer-specific formatting, key mappings, derived speed calculations, and material-specific settings like wipe and retraction.
    export function profileToIniSettings(profile: RecommendedProfile): PrusaSlicerSettings {
      const result: PrusaSlicerSettings = {};
    
      for (const [key, setting] of Object.entries(profile.settings)) {
        const iniKey = KEY_MAP[key] ?? key;
        let value = setting.value;
    
        // PrusaSlicer-specific formatting
        if (key === "infill_density") {
          value = `${value}%`;
        } else if (key === "support_material") {
          value = value ? 1 : 0;
        } else if (key === "first_layer_speed") {
          value = `${value}mm/s`;
        }
    
        result[iniKey] = value;
      }
    
      const printSpeed = profile.settings.print_speed.value as number;
      const lh = profile.settings.layer_height.value as number;
    
      // ─── First layer height ────────────────────────────────────
      // Bible FDM: first layer slightly thicker for better adhesion
      // PrusaSlicer default: typically 0.2mm or same as layer_height
      result["first_layer_height"] = Math.max(lh, 0.2);
    
      // ─── Derived speed settings ────────────────────────────────
      // All speeds derived from perimeter_speed for consistency
      result["infill_speed"] = Math.round(printSpeed * 1.2);          // infill can go faster
      result["solid_infill_speed"] = Math.round(printSpeed * 0.8);    // solid infill slightly slower
      result["top_solid_infill_speed"] = Math.round(printSpeed * 0.5); // top surface = visible, slow
      result["external_perimeter_speed"] = Math.round(printSpeed * 0.5); // external = visible
      result["small_perimeter_speed"] = Math.round(printSpeed * 0.5);
      result["bridge_speed"] = Math.round(printSpeed * 0.4);          // slow for clean bridges
      result["gap_fill_speed"] = Math.round(printSpeed * 0.5);
      result["support_material_speed"] = Math.round(printSpeed * 0.8);
    
      // ─── Retraction settings ───────────────────────────────────
      result["retract_before_travel"] = 2;
      result["retract_lift"] = 0.2;
      result["retract_layer_change"] = 1; // Bible FDM: recommended on
    
      // Wipe: conditionnel — désactivé pour TPU/flexibles (Bible FDM: rétraction délicate)
      const matUpper = profile.material.toUpperCase().replace(/\s*\(.*\)/, ""); // strip "(Polycarbonate)" etc
      result["wipe"] = NO_WIPE_MATERIALS.has(matUpper) ? 0 : 1;
    
      // ─── Top/bottom layers ─────────────────────────────────────
      const shellThickness = 0.8; // mm — standard shell
      const solidLayers = Math.max(3, Math.ceil(shellThickness / lh));
      result["top_solid_layers"] = solidLayers;
      result["bottom_solid_layers"] = solidLayers;
    
      // ─── Nozzle diameter ───────────────────────────────────────
      result["nozzle_diameter"] = profile.nozzle;
    
      // First layer extrusion width (wider for adhesion)
      result["first_layer_extrusion_width"] = Math.round(profile.nozzle * 1.4 * 100) / 100;
    
      // ─── Filament MVS ──────────────────────────────────────────
      result["filament_max_volumetric_speed"] = profile.settings.max_volumetric_speed.value;
    
      // ─── Seam position ─────────────────────────────────────────
      // Bible FDM: seam position matters for blobs/zits — "nearest" reduces travel
      result["seam_position"] = "nearest";
    
      // ─── Elephant foot compensation ────────────────────────────
      // Bible FDM: ajuster si base "écrasée"
      result["elefant_foot_compensation"] = 0.1; // PrusaSlicer uses this exact spelling
    
      // ─── Overhang speed ────────────────────────────────────────
      // Bible FDM: ajuster supports/overhang speed plutôt que fan (surtout ASA)
      result["overhangs"] = 1; // enable overhang detection for speed reduction
    
      return result;
    }

Latest Blog Posts

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Noosbai/PrusaMCP'

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