Skip to main content
Glama
Noosbai
by Noosbai

get_current_model

Retrieves the currently open model in PrusaSlicer, returning file path, active presets, and mesh analysis data for 3D printing workflows.

Instructions

Détecte le fichier actuellement ouvert dans PrusaSlicer en lisant le titre de la fenêtre. Retourne le chemin du fichier, les presets actifs (imprimante, filament, profil), et une analyse complète du mesh si c'est un STL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
analyzeNoLancer l'analyse mesh automatiquement

Implementation Reference

  • Main tool registration and handler implementation for 'get_current_model'. This function registers the tool with its schema (input with 'analyze' boolean) and implements the complete logic: reads PrusaSlicer window title via PowerShell, extracts filename, searches for the file on disk, reads PrusaSlicer.ini state for printer/filament/profile settings, performs optional mesh analysis for STL files using parseStl and analyzeMesh, and returns formatted output with model info and analysis results.
    export function registerGetCurrentModel(server: McpServer, config: PrusaConfig) {
      server.registerTool(
        "get_current_model",
        {
          title: "Voir le modèle ouvert dans PrusaSlicer",
          description:
            "Détecte le fichier actuellement ouvert dans PrusaSlicer en lisant le titre de la fenêtre. " +
            "Retourne le chemin du fichier, les presets actifs (imprimante, filament, profil), " +
            "et une analyse complète du mesh si c'est un STL.",
          inputSchema: {
            analyze: z
              .boolean()
              .default(true)
              .describe("Lancer l'analyse mesh automatiquement"),
          },
        },
        async ({ analyze }) => {
          try {
            const lines: string[] = [];
    
            // 1. Read PrusaSlicer state from ini
            let state: PrusaSlicerState = {
              skeinDirectory: null,
              currentPrinter: null,
              currentFilament: null,
              currentPrintProfile: null,
            };
            if (config.profilesDir) {
              state = await readPrusaSlicerState(config.profilesDir);
            }
    
            // 2. Get window title to find current file
            const windowTitle = await getPrusaSlicerWindowTitle();
    
            if (!windowTitle) {
              return {
                isError: true,
                content: [{
                  type: "text" as const,
                  text: "PrusaSlicer ne semble pas être ouvert. Lance PrusaSlicer et charge un modèle.",
                }],
              };
            }
    
            lines.push("## État PrusaSlicer");
            lines.push(`**Imprimante** : ${state.currentPrinter || "non définie"}`);
            lines.push(`**Filament** : ${state.currentFilament || "non défini"}`);
            lines.push(`**Profil** : ${state.currentPrintProfile || "non défini"}`);
            lines.push("");
    
            // 3. Extract filename from window title
            const fileName = extractFilenameFromTitle(windowTitle);
    
            if (!fileName) {
              lines.push("**Modèle** : Aucun fichier ouvert (projet sans titre)");
              lines.push("");
              lines.push("_Charge un fichier STL/3MF dans PrusaSlicer pour que je puisse l'analyser._");
              return { content: [{ type: "text" as const, text: lines.join("\n") }] };
            }
    
            lines.push(`## Fichier détecté : ${fileName}`);
    
            // 4. Search for the file on disk
            const home = homedir();
            const searchDirs = [
              state.skeinDirectory,
              join(home, "Downloads"),
              join(home, "Bureau"),
              join(home, "Desktop"),
              join(home, "Documents"),
              join(home, "OneDrive", "Bureau"),
              join(home, "OneDrive", "Documents"),
              join(home, "OneDrive", "Downloads"),
            ].filter(Boolean) as string[];
    
            const filePath = await findFileByName(fileName, searchDirs);
    
            if (!filePath) {
              lines.push(`**Chemin** : Fichier "${fileName}" introuvable dans les dossiers habituels.`);
              lines.push(`Dossiers cherchés : ${searchDirs.join(", ")}`);
              lines.push("");
              lines.push("_Donne-moi le chemin complet pour que je puisse l'analyser._");
              return { content: [{ type: "text" as const, text: lines.join("\n") }] };
            }
    
            lines.push(`**Chemin** : ${filePath}`);
    
            // 5. Get file stats
            try {
              const fileStats = await stat(filePath);
              const sizeMB = (fileStats.size / 1024 / 1024).toFixed(2);
              lines.push(`**Taille** : ${sizeMB} MB`);
              lines.push(`**Modifié** : ${fileStats.mtime.toLocaleString()}`);
            } catch { /* skip */ }
    
            lines.push("");
    
            // 6. Analyze mesh if STL
            if (analyze && filePath.toLowerCase().endsWith(".stl")) {
              console.error(`[get_current_model] Analyzing: ${filePath}`);
              const stl = await parseStl(filePath);
              const analysis = analyzeMesh(stl);
              const bb = analysis.boundingBox;
    
              lines.push("## Analyse Mesh");
              lines.push(`**Dimensions** : ${bb.size.x.toFixed(2)} × ${bb.size.y.toFixed(2)} × ${bb.size.z.toFixed(2)} mm`);
              lines.push(`**Volume** : ${analysis.volume.toFixed(2)} mm³ (${(analysis.volume / 1000).toFixed(2)} cm³)`);
              lines.push(`**Surface** : ${analysis.surfaceArea.toFixed(2)} mm²`);
              lines.push(`**Triangles** : ${analysis.triangleCount.toLocaleString()}`);
              lines.push("");
              lines.push(`**Overhangs** : ${analysis.overhangPercent.toFixed(1)}%${analysis.overhangPercent > 5 ? " — supports recommandés" : " — OK, pas de support nécessaire"}`);
              lines.push(`**Manifold** : ${analysis.isManifold ? "OK (mesh fermé)" : "NON — " + analysis.nonManifoldEdges + " arêtes problématiques, repair recommandé"}`);
              lines.push(`**Détails fins** : ${analysis.hasSmallDetails ? "Oui (" + analysis.smallDetailPercent.toFixed(1) + "% de petits triangles)" : "Non"}`);
              lines.push("");
            } else if (filePath.toLowerCase().endsWith(".3mf")) {
              lines.push("_Fichier 3MF détecté — l'analyse mesh n'est disponible que pour les STL pour l'instant._");
            }
    
            // 7. Other recent files in same directory
            const dir = state.skeinDirectory || join(filePath, "..");
            const recentModels = await findRecentModels(dir);
            const others = recentModels.filter((m) => basename(m.path) !== fileName);
            if (others.length > 0) {
              lines.push("## Autres fichiers dans le dossier");
              for (const m of others) {
                lines.push(`- ${basename(m.path)} (${m.mtime.toLocaleString()})`);
              }
            }
    
            return {
              content: [{ type: "text" as const, text: lines.join("\n") }],
            };
          } catch (error) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: `Erreur : ${error instanceof Error ? error.message : String(error)}`,
              }],
            };
          }
        },
      );
    }
  • Helper function getPrusaSlicerWindowTitle that uses PowerShell to read the MainWindowTitle of the prusa-slicer process. Returns null if PrusaSlicer is not running.
    function getPrusaSlicerWindowTitle(): Promise<string | null> {
      return new Promise((resolve) => {
        execFile(
          "powershell",
          [
            "-NoProfile",
            "-Command",
            "Get-Process -Name 'prusa-slicer' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty MainWindowTitle",
          ],
          { timeout: 5000, windowsHide: true },
          (error, stdout) => {
            if (error || !stdout?.trim()) {
              resolve(null);
              return;
            }
            resolve(stdout.trim());
          },
        );
      });
    }
  • Helper function extractFilenameFromTitle that parses PrusaSlicer window title to extract the current filename. Handles various formats including modified files (leading *) and untitled projects.
    function extractFilenameFromTitle(title: string): string | null {
      // Remove the " - PrusaSlicer..." suffix
      const dashIndex = title.indexOf(" - PrusaSlicer");
      if (dashIndex === -1) return null;
    
      let name = title.substring(0, dashIndex).trim();
    
      // Remove leading * (unsaved changes marker)
      if (name.startsWith("*")) name = name.substring(1);
    
      // Check if it's "Sans titre" / "Untitled"
      if (/^sans titre$/i.test(name) || /^untitled$/i.test(name)) {
        return null;
      }
    
      return name;
    }
  • Helper function readPrusaSlicerState that reads PrusaSlicer.ini from the profiles directory and extracts current settings: skein_directory, printer, filament, and print profile.
    async function readPrusaSlicerState(profilesDir: string): Promise<PrusaSlicerState> {
      const iniPath = join(profilesDir, "PrusaSlicer.ini");
      if (!existsSync(iniPath)) {
        return { skeinDirectory: null, currentPrinter: null, currentFilament: null, currentPrintProfile: null };
      }
    
      const content = await readFile(iniPath, "utf-8");
      const state: PrusaSlicerState = {
        skeinDirectory: null,
        currentPrinter: null,
        currentFilament: null,
        currentPrintProfile: null,
      };
    
      const skeinMatch = content.match(/skein_directory\s*=\s*(.+)/);
      if (skeinMatch) state.skeinDirectory = skeinMatch[1].trim();
    
      const printerMatch = content.match(/^printer\s*=\s*(.+)$/m);
      if (printerMatch) state.currentPrinter = printerMatch[1].trim();
    
      const filamentMatch = content.match(/^filament\s*=\s*(.+)$/m);
      if (filamentMatch) state.currentFilament = filamentMatch[1].trim();
    
      const printMatch = content.match(/^print\s*=\s*(.+)$/m);
      if (printMatch) state.currentPrintProfile = printMatch[1].trim();
    
      return state;
    }
  • src/index.ts:59-59 (registration)
    Registration point in main index.ts where registerGetCurrentModel is called with the server instance and config object to enable the tool.
    registerGetCurrentModel(server, config);

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