compare_materials
Compare 2-4 polymer materials side-by-side to evaluate processing, thermal, and mechanical properties. Identifies key differences between thermoplastics to support material selection decisions for injection molding.
Instructions
Compare 2-4 materials side-by-side. Returns a table of processing, thermal, and mechanical properties with key differences highlighted. Available materials: abs-generic, pp-homo, pp-copo, pa6, pa66, pa66-gf30, pc, pc-abs, pom, hdpe, ldpe, pmma, pbt, pbt-gf30, pet, ps, hips, tpu, san, asa, ppe-ps
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| materials | Yes | List of material IDs to compare (e.g., ["abs-generic", "pc", "pa66-gf30"]) |
Implementation Reference
- src/tools/compare-materials.ts:3-74 (handler)Main compareMaterials function - takes materialIds array, validates input (2-4 materials), looks up materials, and generates a formatted comparison table with processing, thermal, and mechanical properties plus key differences analysis
export function compareMaterials(materialIds: string[]): string { if (materialIds.length < 2) { return 'Please provide at least 2 material IDs to compare.'; } if (materialIds.length > 4) { return 'Maximum 4 materials can be compared at once. Please reduce the list.'; } const results: { query: string; material: Material | null }[] = materialIds.map(id => { const matches = findMaterial(id); return { query: id, material: matches[0] ?? null }; }); const notFound = results.filter(r => !r.material); if (notFound.length > 0) { return [ `Materials not found: ${notFound.map(r => `"${r.query}"`).join(', ')}`, '', 'Use get_material_properties to list available material IDs.', ].join('\n'); } const mats = results.map(r => r.material!); const lines: string[] = []; lines.push(`# Material Comparison: ${mats.map(m => m.name).join(' vs ')}\n`); // General info lines.push('## General'); lines.push(row('Family', mats.map(m => m.family))); lines.push(row('Type', mats.map(m => m.type))); lines.push(row('Filler', mats.map(m => m.filler ? `${m.filler} (${m.filler_pct}%)` : '—'))); // Processing window lines.push('\n## Processing Window'); lines.push(row('Melt temp range', mats.map(m => `${m.processing.melt_temp_min_C}–${m.processing.melt_temp_max_C}°C`))); lines.push(row('Melt temp (rec)', mats.map(m => `${m.processing.melt_temp_recommended_C}°C`))); lines.push(row('Mold temp range', mats.map(m => `${m.processing.mold_temp_min_C}–${m.processing.mold_temp_max_C}°C`))); lines.push(row('Mold temp (rec)', mats.map(m => `${m.processing.mold_temp_recommended_C}°C`))); lines.push(row('Max shear rate', mats.map(m => `${m.processing.max_shear_rate_1_s} 1/s`))); lines.push(row('Drying', mats.map(m => m.processing.drying_temp_C != null ? `${m.processing.drying_temp_C}°C / ${m.processing.drying_time_hr}h` : 'Not required' ))); lines.push(row('Max residence', mats.map(m => `${m.processing.max_residence_time_min} min`))); // Thermal lines.push('\n## Thermal Properties'); lines.push(row('Conductivity', mats.map(m => `${m.thermal.thermal_conductivity_W_mK} W/(m·K)`))); lines.push(row('Specific heat', mats.map(m => `${m.thermal.specific_heat_J_kgK} J/(kg·K)`))); lines.push(row('Density', mats.map(m => `${m.thermal.density_kg_m3} kg/m³`))); lines.push(row('Ejection temp', mats.map(m => `${m.thermal.ejection_temp_C}°C`))); lines.push(row('No-flow temp', mats.map(m => `${m.thermal.no_flow_temp_C}°C`))); // Mechanical lines.push('\n## Mechanical Properties'); lines.push(row('Tensile strength', mats.map(m => `${m.mechanical.tensile_strength_MPa} MPa`))); lines.push(row('Flexural modulus', mats.map(m => `${m.mechanical.flexural_modulus_MPa} MPa`))); lines.push(row('Elongation', mats.map(m => `${m.mechanical.elongation_at_break_pct}%`))); lines.push(row('HDT @ 1.8 MPa', mats.map(m => `${m.mechanical.HDT_at_1_8MPa_C}°C`))); lines.push(row('Shrinkage', mats.map(m => `${m.mechanical.shrinkage_pct_min}–${m.mechanical.shrinkage_pct_max}%`))); // Key differences lines.push('\n## Key Differences'); lines.push(...generateKeyDifferences(mats)); lines.push('\n---'); lines.push('*Data from MoldSim MCP material database. Verify against supplier datasheets for your specific grade.*'); return lines.join('\n'); } - src/server.ts:79-88 (registration)Tool registration for compare_materials using server.tool() with Zod schema validation - registers with MCP server
server.tool( 'compare_materials', `Compare 2-4 materials side-by-side. Returns a table of processing, thermal, and mechanical properties with key differences highlighted. Available materials: ${listMaterials().map(m => m.id).join(', ')}`, { materials: z.array(z.string()).min(2).max(4).describe('List of material IDs to compare (e.g., ["abs-generic", "pc", "pa66-gf30"])'), }, async ({ materials }) => ({ content: [{ type: 'text', text: compareMaterials(materials) }], }) ); - src/server.ts:82-84 (schema)Zod input validation schema for compare_materials - validates materials array must have 2-4 string items
{ materials: z.array(z.string()).min(2).max(4).describe('List of material IDs to compare (e.g., ["abs-generic", "pc", "pa66-gf30"])'), }, - src/knowledge/materials.ts:74-89 (helper)Material interface/type definition used by compareMaterials - defines structure for material properties including processing, thermal, and mechanical data
export interface Material { id: string; name: string; family: string; type: 'amorphous' | 'semi-crystalline'; filler?: string; filler_pct?: number; mfi_g_10min?: number; mfi_condition?: string; cross_wlf: CrossWLF; tait_pvt: TaitPVT; thermal: ThermalProperties; processing: ProcessingWindow; mechanical: MechanicalProperties; notes: string; } - src/knowledge/materials.ts:1117-1135 (helper)findMaterial helper function - searches material database by ID/name/family with scoring, returns array of matching Material objects
export function findMaterial(query: string): Material[] { const q = query.toLowerCase().replace(/[^a-z0-9]/g, ''); if (!q) return []; const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, ''); const scored = MATERIALS.map(m => { const id = norm(m.id); const name = norm(m.name); const family = norm(m.family); const filler = norm(m.filler ?? ''); if (id === q) return { m, score: 100 }; if (id.startsWith(q) || q.startsWith(id)) return { m, score: 80 }; if (id.includes(q) || name.includes(q)) return { m, score: 60 }; if (family === q) return { m, score: 50 }; if (family.includes(q)) return { m, score: 30 }; if (filler.length > 0 && filler.includes(q)) return { m, score: 20 }; return { m, score: 0 }; }).filter(({ score }) => score > 0);