Recommend Material
recommend_materialSelect project requirements like strength, flexibility, heat resistance, food safety, outdoor use, ease of printing, and budget to get ranked material suggestions with explanations.
Instructions
Recommend the best 3D printing material based on project requirements. Describe what you need (strength, flexibility, heat resistance, food safety, outdoor use, ease of printing, budget) and get ranked material suggestions with explanations.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| requirements | Yes | Project requirements for material selection |
Implementation Reference
- src/tools/recommend-material.ts:311-405 (handler)The async handler function that receives user requirements, scores all materials using helper scoring functions, sorts by score, and returns formatted recommendations.
async ({ requirements }) => { // Check if any requirements provided const hasRequirements = Object.values(requirements).some( (v) => v !== undefined && v !== null, ); if (!hasRequirements) { return { isError: true, content: [ { type: 'text' as const, text: 'Please provide at least one requirement (strength, flexibility, heat_resistance, food_safe, outdoor_use, ease_of_printing, or budget).', }, ], }; } const profiles = getAllMaterialProfiles(db); const scored: ScoredMaterial[] = profiles.map((profile) => { let score = 0; const reasons: string[] = []; const caveats: string[] = []; if (requirements.strength) { const r = scoreStrength(profile, requirements.strength); score += r.score; reasons.push(r.reason); } if (requirements.flexibility) { const r = scoreFlexibility(profile, requirements.flexibility); score += r.score; reasons.push(r.reason); } if (requirements.heat_resistance) { const r = scoreHeatResistance(profile, requirements.heat_resistance); score += r.score; reasons.push(r.reason); if (r.caveat) { caveats.push(r.caveat); } } if (requirements.food_safe) { const r = scoreFoodSafe(profile); score += r.score; reasons.push(r.reason); if (r.score === 0) { caveats.push('Not suitable for food contact'); } } if (requirements.outdoor_use) { const r = scoreOutdoor(profile); score += r.score; reasons.push(r.reason); if (r.score <= pct(0.2, WEIGHTS.outdoor)) { caveats.push('Poor outdoor durability'); } } if (requirements.ease_of_printing) { const r = scoreEase(profile, requirements.ease_of_printing); score += r.score; reasons.push(r.reason); } if (requirements.budget) { const r = scoreBudget(profile, requirements.budget); score += r.score; reasons.push(r.reason); } return { profile, score, reasons, caveats }; }); // Sort by score descending scored.sort((a, b) => b.score - a.score); const lines = ['# Material Recommendations', '']; scored.forEach((s, i) => { lines.push(`${i + 1}. **${s.profile.material_name}** (score: ${s.score})`); for (const reason of s.reasons) { lines.push(` - ${reason}`); } if (s.caveats.length > 0) { lines.push(` - Caveats: ${s.caveats.join('; ')}`); } lines.push(''); }); return { content: [{ type: 'text' as const, text: lines.join('\n') }] }; }, ); - Input schema definition for the recommend_material tool, defining all optional requirements fields (strength, flexibility, heat_resistance, food_safe, outdoor_use, ease_of_printing, budget) with Zod enums.
inputSchema: { requirements: z.object({ strength: z .enum(['low', 'medium', 'high']) .optional() .describe('Required mechanical strength'), flexibility: z .enum(['rigid', 'semi-flexible', 'flexible']) .optional() .describe('Required flexibility'), heat_resistance: z .enum(['low', 'medium', 'high']) .optional() .describe('Required heat resistance'), food_safe: z .boolean() .optional() .describe('Must be food-safe material'), outdoor_use: z .boolean() .optional() .describe('Will be used outdoors (needs UV resistance)'), ease_of_printing: z .enum(['beginner', 'intermediate', 'advanced']) .optional() .describe('Desired printing difficulty level'), budget: z .enum(['low', 'medium', 'high']) .optional() .describe('Budget constraint'), }).describe('Project requirements for material selection'), }, - src/tools/recommend-material.ts:268-406 (registration)The registerRecommendMaterial function that registers the tool named 'recommend_material' on the MCP server with its schema and handler.
export function registerRecommendMaterial( server: McpServer, db: Database.Database, ): void { server.registerTool( 'recommend_material', { title: 'Recommend Material', description: 'Recommend the best 3D printing material based on project requirements. Describe what you need (strength, flexibility, heat resistance, food safety, outdoor use, ease of printing, budget) and get ranked material suggestions with explanations.', inputSchema: { requirements: z.object({ strength: z .enum(['low', 'medium', 'high']) .optional() .describe('Required mechanical strength'), flexibility: z .enum(['rigid', 'semi-flexible', 'flexible']) .optional() .describe('Required flexibility'), heat_resistance: z .enum(['low', 'medium', 'high']) .optional() .describe('Required heat resistance'), food_safe: z .boolean() .optional() .describe('Must be food-safe material'), outdoor_use: z .boolean() .optional() .describe('Will be used outdoors (needs UV resistance)'), ease_of_printing: z .enum(['beginner', 'intermediate', 'advanced']) .optional() .describe('Desired printing difficulty level'), budget: z .enum(['low', 'medium', 'high']) .optional() .describe('Budget constraint'), }).describe('Project requirements for material selection'), }, }, async ({ requirements }) => { // Check if any requirements provided const hasRequirements = Object.values(requirements).some( (v) => v !== undefined && v !== null, ); if (!hasRequirements) { return { isError: true, content: [ { type: 'text' as const, text: 'Please provide at least one requirement (strength, flexibility, heat_resistance, food_safe, outdoor_use, ease_of_printing, or budget).', }, ], }; } const profiles = getAllMaterialProfiles(db); const scored: ScoredMaterial[] = profiles.map((profile) => { let score = 0; const reasons: string[] = []; const caveats: string[] = []; if (requirements.strength) { const r = scoreStrength(profile, requirements.strength); score += r.score; reasons.push(r.reason); } if (requirements.flexibility) { const r = scoreFlexibility(profile, requirements.flexibility); score += r.score; reasons.push(r.reason); } if (requirements.heat_resistance) { const r = scoreHeatResistance(profile, requirements.heat_resistance); score += r.score; reasons.push(r.reason); if (r.caveat) { caveats.push(r.caveat); } } if (requirements.food_safe) { const r = scoreFoodSafe(profile); score += r.score; reasons.push(r.reason); if (r.score === 0) { caveats.push('Not suitable for food contact'); } } if (requirements.outdoor_use) { const r = scoreOutdoor(profile); score += r.score; reasons.push(r.reason); if (r.score <= pct(0.2, WEIGHTS.outdoor)) { caveats.push('Poor outdoor durability'); } } if (requirements.ease_of_printing) { const r = scoreEase(profile, requirements.ease_of_printing); score += r.score; reasons.push(r.reason); } if (requirements.budget) { const r = scoreBudget(profile, requirements.budget); score += r.score; reasons.push(r.reason); } return { profile, score, reasons, caveats }; }); // Sort by score descending scored.sort((a, b) => b.score - a.score); const lines = ['# Material Recommendations', '']; scored.forEach((s, i) => { lines.push(`${i + 1}. **${s.profile.material_name}** (score: ${s.score})`); for (const reason of s.reasons) { lines.push(` - ${reason}`); } if (s.caveats.length > 0) { lines.push(` - Caveats: ${s.caveats.join('; ')}`); } lines.push(''); }); return { content: [{ type: 'text' as const, text: lines.join('\n') }] }; }, ); } - src/server.ts:16-16 (registration)Import of registerRecommendMaterial from the recommend-material module.
import { registerRecommendMaterial } from './tools/recommend-material.js'; - src/server.ts:49-49 (registration)Call to registerRecommendMaterial to wire up the tool in the server.
registerRecommendMaterial(server, db);