estimate_cost
Calculate 3D printing costs for filament, electricity, and time. Compare draft, standard, and quality profiles side by side.
Instructions
Estime le coût d'impression d'un modèle 3D : filament, électricité, temps. Peut aussi comparer plusieurs profils (draft/standard/quality) côte à côte.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Chemin absolu vers le fichier STL ou 3MF | |
| material | No | Matériau (PLA, PETG, ABS...) | PLA |
| nozzle | No | Diamètre de buse en mm | |
| filament_price_per_kg | No | Prix du filament en EUR/kg | |
| electricity_price | No | Prix électricité en EUR/kWh | |
| compare_profiles | No | Comparer draft/standard/quality côte à côte |
Implementation Reference
- src/tools/estimate-cost.ts:9-133 (handler)Main tool registration and handler for estimate_cost. Defines the tool schema (file_path, material, nozzle, filament_price_per_kg, electricity_price, compare_profiles) and contains the complete handler logic that parses mesh files, analyzes them, and calls estimateCostFromMesh to compute costs. Supports both single profile and multi-profile comparison modes.
export function registerEstimateCost(server: McpServer) { server.registerTool( "estimate_cost", { title: "Estimer le coût d'impression", description: "Estime le coût d'impression d'un modèle 3D : filament, électricité, temps. " + "Peut aussi comparer plusieurs profils (draft/standard/quality) côte à côte.", inputSchema: { file_path: z.string().describe("Chemin absolu vers le fichier STL ou 3MF"), material: z.string().default("PLA").describe("Matériau (PLA, PETG, ABS...)"), nozzle: z.number().default(0.4).describe("Diamètre de buse en mm"), filament_price_per_kg: z.number().default(22).describe("Prix du filament en EUR/kg"), electricity_price: z.number().default(0.25).describe("Prix électricité en EUR/kWh"), compare_profiles: z .boolean() .default(true) .describe("Comparer draft/standard/quality côte à côte"), }, }, async ({ file_path, material, nozzle, filament_price_per_kg, electricity_price, compare_profiles }) => { try { if (!existsSync(file_path)) { return { isError: true, content: [{ type: "text" as const, text: `Fichier non trouvé : ${file_path}` }], }; } const mesh = await parseModel(file_path); const analysis = analyzeMesh(mesh); const params = { filamentPricePerKg: filament_price_per_kg, electricityPricePerKwh: electricity_price, printerWattage: 200, }; const lines: string[] = []; if (compare_profiles) { // Compare draft / standard / quality const goals = ["draft", "standard", "quality", "strong"] as const; const comparisons: Array<{ name: string; time: string; cost: string; filament: string; layerH: number; }> = []; lines.push("## Comparaison des profils"); lines.push(`**Modèle** : ${mesh.name} | **Matériau** : ${material} | **Buse** : ${nozzle}mm`); lines.push(`**Prix filament** : ${filament_price_per_kg}€/kg | **Électricité** : ${electricity_price}€/kWh`); lines.push(""); for (const goal of goals) { const profile = recommendProfile("Generic", nozzle, goal, material); const lh = profile.settings.layer_height.value as number; const infill = profile.settings.infill_density.value as number; const perimeters = profile.settings.perimeters.value as number; const speed = profile.settings.print_speed.value as number; const estimate = estimateCostFromMesh( analysis, lh, infill, perimeters, speed, material, params, ); comparisons.push({ name: goal, time: estimate.printTimeFormatted, cost: `${estimate.totalCostEur}€`, filament: `${estimate.filamentWeightG}g`, layerH: lh, }); } // Table lines.push("| Profil | Layer | Temps | Filament | Coût total |"); lines.push("|--------|-------|-------|----------|------------|"); for (const c of comparisons) { lines.push(`| **${c.name}** | ${c.layerH}mm | ${c.time} | ${c.filament} | ${c.cost} |`); } // Savings if (comparisons.length >= 2) { const fastest = comparisons[0]; const slowest = comparisons[comparisons.length - 1]; lines.push(""); lines.push(`**Économie draft vs strong** : ${slowest.cost} → ${fastest.cost} en passant de ${slowest.time} à ${fastest.time}`); } } else { // Single profile estimate const profile = recommendProfile("Generic", nozzle, "standard", material); const lh = profile.settings.layer_height.value as number; const infill = profile.settings.infill_density.value as number; const perimeters = profile.settings.perimeters.value as number; const speed = profile.settings.print_speed.value as number; const estimate = estimateCostFromMesh( analysis, lh, infill, perimeters, speed, material, params, ); lines.push("## Estimation de coût"); lines.push(`**Temps** : ${estimate.printTimeFormatted}`); lines.push(`**Filament** : ${estimate.filamentWeightG}g (${estimate.filamentLengthMm.toFixed(0)}mm)`); lines.push(`**Coût filament** : ${estimate.filamentCostEur}€`); lines.push(`**Coût électricité** : ${estimate.electricityCostEur}€`); lines.push(`**Coût total** : ${estimate.totalCostEur}€`); } 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)}`, }], }; } }, ); } - src/cost-estimator.ts:66-120 (handler)Core implementation of estimateCostFromMesh function that performs the actual cost calculation. Takes mesh analysis data, printing parameters (layer height, infill, perimeters, speed), material type, and pricing parameters. Calculates filament volume (shell, infill, top/bottom solid layers), weight, length, print time, and costs (filament + electricity).
export function estimateCostFromMesh( analysis: MeshAnalysis, layerHeight: number, infillPercent: number, perimeters: number, printSpeed: number, material: string = "PLA", params: Partial<CostParams> = {}, filamentDiameter: number = 1.75, ): CostEstimate { const density = params.filamentDensity ?? MATERIAL_DENSITY[material.toUpperCase()] ?? 1.24; const pricePerKg = params.filamentPricePerKg ?? DEFAULT_FILAMENT_PRICE; const electricityPrice = params.electricityPricePerKwh ?? 0.25; const wattage = params.printerWattage ?? 200; // Estimate filament volume: // Shell volume = surface area × perimeters × line width (≈ nozzle diameter) const lineWidth = 0.45; // approximate const shellVolume = analysis.surfaceArea * perimeters * lineWidth; // mm³ // Infill volume = (total volume - shell volume) × infill% const innerVolume = Math.max(0, analysis.volume - shellVolume); const infillVolume = innerVolume * (infillPercent / 100); // Top/bottom solid layers (assume 4 each at layer_height) const topBottomArea = analysis.boundingBox.size.x * analysis.boundingBox.size.y; const solidVolume = topBottomArea * layerHeight * 8; // 4 top + 4 bottom const totalFilamentVolume = shellVolume + infillVolume + solidVolume; // mm³ const weightG = (totalFilamentVolume / 1000) * density; // mm³ to cm³ then × g/cm³ // Filament length (1.75mm or 2.85mm diameter) const filamentCrossSectionMm2 = Math.PI * (filamentDiameter / 2) ** 2; const lengthMm = totalFilamentVolume / filamentCrossSectionMm2; // Time estimate: total volume / (line width × layer height × speed) const extrusionRate = lineWidth * layerHeight * printSpeed; // mm³/s const printTimeSeconds = extrusionRate > 0 ? (totalFilamentVolume / extrusionRate) * 1.3 // 1.3× factor for travel moves : 0; const filamentCost = (weightG / 1000) * pricePerKg; const printTimeHours = printTimeSeconds / 3600; const electricityCost = (wattage / 1000) * printTimeHours * electricityPrice; return { filamentWeightG: round2(weightG), filamentLengthMm: round2(lengthMm), filamentCostEur: round2(filamentCost), electricityCostEur: round2(electricityCost), totalCostEur: round2(filamentCost + electricityCost), printTimeSeconds: Math.round(printTimeSeconds), printTimeFormatted: formatTime(printTimeSeconds), }; } - src/cost-estimator.ts:3-18 (schema)Type definitions for cost estimation. Defines CostEstimate interface (output structure with filamentWeightG, filamentLengthMm, filamentCostEur, electricityCostEur, totalCostEur, printTimeSeconds, printTimeFormatted) and CostParams interface (input parameters including filamentPricePerKg, filamentDensity, electricityPricePerKwh, printerWattage).
export interface CostEstimate { filamentWeightG: number; filamentLengthMm: number; filamentCostEur: number; electricityCostEur: number; totalCostEur: number; printTimeSeconds: number; printTimeFormatted: string; } export interface CostParams { filamentPricePerKg: number; // EUR/kg filamentDensity: number; // g/cm³ (PLA ≈ 1.24, PETG ≈ 1.27, ABS ≈ 1.04) electricityPricePerKwh: number; // EUR/kWh printerWattage: number; // watts during printing } - src/index.ts:16-47 (registration)Tool registration in the main server file. Imports registerEstimateCost from tools/estimate-cost.js and calls registerEstimateCost(server) at line 47 to register the estimate_cost tool with the MCP server.
import { registerEstimateCost } from "./tools/estimate-cost.js"; import { registerPostprocessGcode } from "./tools/postprocess-gcode.js"; import { registerUploadPrint } from "./tools/upload-print.js"; import { registerSearchFilament } from "./tools/search-filament.js"; import { registerPrintWizard } from "./tools/print-wizard.js"; import { registerSubmitFeedback, registerFeedbackStats, registerExportFeedback } from "./tools/feedback.js"; import { registerDiagnosePrint } from "./tools/diagnose-print.js"; async function main() { console.error("PrusaMCP v2.1.0 — MCP Server intelligent pour PrusaSlicer"); const config = loadConfig(); if (config.executablePath) { console.error(`PrusaSlicer : ${config.executablePath}`); } if (config.profilesDir) { console.error(`Profils : ${config.profilesDir}`); } const server = new McpServer({ name: "prusa-mcp", version: "2.1.0", }); // Analyse & recommandation (sans PrusaSlicer) registerAnalyzeMesh(server); registerCheckPrintability(server); registerSuggestOrientation(server); registerRecommendProfile(server); registerGenerateConfig(server); registerEstimateCost(server); - src/cost-estimator.ts:122-134 (helper)Helper utility functions for cost estimation. Includes round2() for rounding values to 2 decimal places and formatTime() for converting seconds to human-readable time format (e.g., '2h 30min', '45min 20s').
function round2(v: number): number { return Math.round(v * 100) / 100; } function formatTime(seconds: number): string { if (seconds <= 0) return "N/A"; const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const s = Math.round(seconds % 60); if (h > 0) return `${h}h ${m}min`; if (m > 0) return `${m}min ${s}s`; return `${s}s`; }