Search Filaments
search_filamentsSearch 7,000+ 3D printing filaments by name, material, manufacturer, or color. Each result includes an ID for retrieving detailed specifications.
Instructions
Search 7,000+ 3D printing filaments by name, material type, manufacturer, or color. Each result is prefixed with [ID ] — pass that ID to get_filament for full specs (the ID is the only unambiguous lookup key, since many filaments share names like "Black" or "Jade White").
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search text (filament name, material, manufacturer, or color) | |
| material | No | Filter by material type (e.g., "PLA", "PETG", "ABS") | |
| manufacturer | No | Filter by manufacturer name | |
| diameter | No | Filter by filament diameter in mm (1.75 or 2.85) | |
| limit | No | Max results (1-100, default 20) | |
| offset | No | Pagination offset |
Implementation Reference
- src/tools/search-filaments.ts:77-117 (handler)The async handler function that executes the 'search_filaments' tool logic. Calls searchFilaments() from db.ts and formats results.
async ({ query, material, manufacturer, diameter, limit, offset }) => { const clampedLimit = Math.max(1, Math.min(limit, 100)); const result = searchFilaments( db, query, { material, manufacturer, diameter }, clampedLimit, offset, ); if (result.total === 0) { return { isError: true, content: [ { type: 'text' as const, text: `No filaments found matching your search. Try broadening your query or use search_filaments with different filters.`, }, ], }; } const showing = result.rows.length; const lines: string[] = []; lines.push( `Found ${result.total} result${result.total === 1 ? '' : 's'}. Showing ${offset + 1}-${offset + showing} of ${result.total}. Use the [ID] from any row with get_filament for full details.\n`, ); for (const row of result.rows) { lines.push(formatFilament(row)); } if (offset + showing < result.total) { lines.push( `\n--- Page ${Math.floor(offset / clampedLimit) + 1} of ${Math.ceil(result.total / clampedLimit)}. Use offset=${offset + clampedLimit} for next page. ---`, ); } return { content: [{ type: 'text' as const, text: lines.join('\n') }] }; }, ); - src/tools/search-filaments.ts:41-76 (schema)Registration of the tool with name 'search_filaments' including input schema (query, material, manufacturer, diameter, limit, offset).
server.registerTool( 'search_filaments', { title: 'Search Filaments', description: 'Search 7,000+ 3D printing filaments by name, material type, manufacturer, or color. Each result is prefixed with [ID <n>] — pass that ID to get_filament for full specs (the ID is the only unambiguous lookup key, since many filaments share names like "Black" or "Jade White").', inputSchema: { query: z .string() .describe( 'Search text (filament name, material, manufacturer, or color)', ), material: z .string() .optional() .describe('Filter by material type (e.g., "PLA", "PETG", "ABS")'), manufacturer: z .string() .optional() .describe('Filter by manufacturer name'), diameter: z .number() .optional() .describe('Filter by filament diameter in mm (1.75 or 2.85)'), limit: z .number() .optional() .default(20) .describe('Max results (1-100, default 20)'), offset: z .number() .optional() .default(0) .describe('Pagination offset'), }, }, - src/server.ts:43-43 (registration)Registration call: registerSearchFilaments(server, db) wires the tool into the MCP server.
registerSearchFilaments(server, db); - src/tools/search-filaments.ts:6-35 (helper)formatFilament helper — formats a FilamentRow as a human-readable string with ID, temperatures, diameter, and color.
function formatFilament(f: FilamentRow): string { const lines: string[] = []; // Show ID prominently — it is the unambiguous lookup key for get_filament. // The `name` field in SpoolmanDB is often just the colour (e.g. "Jade White") // and is shared across manufacturers and materials, so the full label below // is for human reading; the ID is what get_filament should be called with. lines.push(`- [ID ${f.id}] ${f.manufacturer_name} — ${f.material_name} — ${f.name}`); const tempParts: string[] = []; if (f.extruder_temp != null) { let tempStr = `Extruder: ${f.extruder_temp}°C`; if (f.extruder_temp_min != null && f.extruder_temp_max != null) { tempStr += ` (${f.extruder_temp_min}-${f.extruder_temp_max}°C)`; } tempParts.push(tempStr); } if (f.bed_temp != null) { tempParts.push(`Bed: ${f.bed_temp}°C`); } if (tempParts.length > 0) { lines.push(` ${tempParts.join(' | ')}`); } const detailParts: string[] = [`${f.diameter}mm`]; if (f.color_name) detailParts.push(`Color: ${f.color_name}`); if (f.color_hex) detailParts.push(`#${f.color_hex}`); lines.push(` ${detailParts.join(' | ')}`); return lines.join('\n'); } - src/data/db.ts:94-156 (helper)searchFilaments database function — performs full-text search via FTS5 across filaments table with optional filters (material, manufacturer, diameter) and pagination.
export function searchFilaments( db: Database.Database, query: string, filters: SearchFilters = {}, limit = 20, offset = 0, ): SearchResult { const conditions: string[] = []; const params: (string | number)[] = []; // FTS match const sanitized = sanitizeFtsQuery(query); if (sanitized.length > 0) { // Add wildcard suffix for prefix matching const ftsTerms = sanitized .split(/\s+/) .filter(Boolean) .map((t) => `"${t}"*`) .join(' '); conditions.push( 'f.id IN (SELECT rowid FROM filaments_fts WHERE filaments_fts MATCH ?)', ); params.push(ftsTerms); } // Filters if (filters.material) { conditions.push('f.material_name = ?'); params.push(filters.material); } if (filters.manufacturer) { conditions.push('m.name = ?'); params.push(filters.manufacturer); } if (filters.diameter) { conditions.push('f.diameter = ?'); params.push(filters.diameter); } const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; // Total count const countSql = ` SELECT COUNT(*) AS cnt FROM filaments f JOIN manufacturers m ON f.manufacturer_id = m.id ${where} `; const { cnt } = db.prepare(countSql).get(...params) as { cnt: number }; // Page of results const dataSql = ` ${FILAMENT_BASE_SELECT} ${where} ORDER BY f.name LIMIT ? OFFSET ? `; const rows = db .prepare(dataSql) .all(...params, limit, offset) as FilamentRow[]; return { rows, total: cnt }; }