3dprint-oracle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/data/3dprint.sqlite +0 -0
  4. package/dist/data/db.d.ts +88 -0
  5. package/dist/data/db.d.ts.map +1 -0
  6. package/dist/data/db.js +175 -0
  7. package/dist/data/db.js.map +1 -0
  8. package/dist/data/schema.sql +86 -0
  9. package/dist/server.d.ts +8 -0
  10. package/dist/server.d.ts.map +1 -0
  11. package/dist/server.js +58 -0
  12. package/dist/server.js.map +1 -0
  13. package/dist/tools/compare-materials.d.ts +4 -0
  14. package/dist/tools/compare-materials.d.ts.map +1 -0
  15. package/dist/tools/compare-materials.js +79 -0
  16. package/dist/tools/compare-materials.js.map +1 -0
  17. package/dist/tools/diagnose-print-issue.d.ts +4 -0
  18. package/dist/tools/diagnose-print-issue.d.ts.map +1 -0
  19. package/dist/tools/diagnose-print-issue.js +58 -0
  20. package/dist/tools/diagnose-print-issue.js.map +1 -0
  21. package/dist/tools/get-filament.d.ts +4 -0
  22. package/dist/tools/get-filament.d.ts.map +1 -0
  23. package/dist/tools/get-filament.js +95 -0
  24. package/dist/tools/get-filament.js.map +1 -0
  25. package/dist/tools/get-material-profile.d.ts +4 -0
  26. package/dist/tools/get-material-profile.d.ts.map +1 -0
  27. package/dist/tools/get-material-profile.js +57 -0
  28. package/dist/tools/get-material-profile.js.map +1 -0
  29. package/dist/tools/list-manufacturers.d.ts +4 -0
  30. package/dist/tools/list-manufacturers.d.ts.map +1 -0
  31. package/dist/tools/list-manufacturers.js +32 -0
  32. package/dist/tools/list-manufacturers.js.map +1 -0
  33. package/dist/tools/list-materials.d.ts +4 -0
  34. package/dist/tools/list-materials.d.ts.map +1 -0
  35. package/dist/tools/list-materials.js +25 -0
  36. package/dist/tools/list-materials.js.map +1 -0
  37. package/dist/tools/recommend-material.d.ts +4 -0
  38. package/dist/tools/recommend-material.d.ts.map +1 -0
  39. package/dist/tools/recommend-material.js +195 -0
  40. package/dist/tools/recommend-material.js.map +1 -0
  41. package/dist/tools/search-filaments.d.ts +4 -0
  42. package/dist/tools/search-filaments.d.ts.map +1 -0
  43. package/dist/tools/search-filaments.js +86 -0
  44. package/dist/tools/search-filaments.js.map +1 -0
  45. package/package.json +49 -0
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ import { getTroubleshooting, getAvailableSymptoms, } from '../data/db.js';
3
+ export function registerDiagnosePrintIssue(server, db) {
4
+ server.registerTool('diagnose_print_issue', {
5
+ title: 'Diagnose Print Issue',
6
+ description: 'Diagnose a 3D printing problem by symptom. Returns possible causes ranked by probability, with specific fixes for each. Optionally filter by material type for material-specific troubleshooting.',
7
+ inputSchema: {
8
+ symptom: z
9
+ .string()
10
+ .describe('The print issue symptom (e.g., "stringing", "warping", "layer_adhesion", "clogging", "elephant_foot")'),
11
+ material: z
12
+ .string()
13
+ .optional()
14
+ .describe('Material type for material-specific diagnosis (e.g., "PLA", "PETG")'),
15
+ },
16
+ }, async ({ symptom, material }) => {
17
+ const entries = getTroubleshooting(db, symptom.toLowerCase(), material);
18
+ if (entries.length === 0) {
19
+ const available = getAvailableSymptoms(db);
20
+ return {
21
+ isError: true,
22
+ content: [
23
+ {
24
+ type: 'text',
25
+ text: `No troubleshooting data found for symptom "${symptom}". Available symptoms: ${available.join(', ')}`,
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ // Sort: material-specific first, then by probability
31
+ const probOrder = { high: 0, medium: 1, low: 2 };
32
+ const sorted = [...entries].sort((a, b) => {
33
+ // Material-specific entries first when material is provided
34
+ if (material) {
35
+ const aSpecific = a.material_name ? 0 : 1;
36
+ const bSpecific = b.material_name ? 0 : 1;
37
+ if (aSpecific !== bSpecific)
38
+ return aSpecific - bSpecific;
39
+ }
40
+ return (probOrder[a.probability] ?? 1) - (probOrder[b.probability] ?? 1);
41
+ });
42
+ const header = material
43
+ ? `# Diagnosing "${symptom}" (${material})`
44
+ : `# Diagnosing "${symptom}"`;
45
+ const lines = [header, ''];
46
+ for (const entry of sorted) {
47
+ const materialTag = entry.material_name
48
+ ? ` [${entry.material_name}-specific]`
49
+ : '';
50
+ lines.push(`## ${entry.cause}${materialTag}`);
51
+ lines.push(`- Probability: ${entry.probability}`);
52
+ lines.push(`- Fix: ${entry.fix}`);
53
+ lines.push('');
54
+ }
55
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
56
+ });
57
+ }
58
+ //# sourceMappingURL=diagnose-print-issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose-print-issue.js","sourceRoot":"","sources":["../../src/tools/diagnose-print-issue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerGetFilament(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=get-filament.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-filament.d.ts","sourceRoot":"","sources":["../../src/tools/get-filament.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAqD3C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CAkDN"}
@@ -0,0 +1,95 @@
1
+ import { z } from 'zod';
2
+ import { getFilamentById, getFilamentByName, } from '../data/db.js';
3
+ function formatFilamentDetail(f) {
4
+ const lines = [];
5
+ lines.push(`# ${f.name}`);
6
+ lines.push('');
7
+ lines.push(`Manufacturer: ${f.manufacturer_name}`);
8
+ lines.push(`Material: ${f.material_name}`);
9
+ lines.push(`Diameter: ${f.diameter}mm`);
10
+ if (f.density != null)
11
+ lines.push(`Density: ${f.density} g/cm³`);
12
+ if (f.weight != null)
13
+ lines.push(`Spool Weight: ${f.weight}g`);
14
+ if (f.spool_weight != null)
15
+ lines.push(`Spool (empty) Weight: ${f.spool_weight}g`);
16
+ lines.push('');
17
+ lines.push('## Temperatures');
18
+ if (f.extruder_temp != null) {
19
+ lines.push(`Extruder: ${f.extruder_temp}°C`);
20
+ if (f.extruder_temp_min != null && f.extruder_temp_max != null) {
21
+ lines.push(`Extruder Range: ${f.extruder_temp_min}-${f.extruder_temp_max}°C`);
22
+ }
23
+ }
24
+ if (f.bed_temp != null) {
25
+ lines.push(`Bed: ${f.bed_temp}°C`);
26
+ if (f.bed_temp_min != null && f.bed_temp_max != null) {
27
+ lines.push(`Bed Range: ${f.bed_temp_min}-${f.bed_temp_max}°C`);
28
+ }
29
+ }
30
+ if (f.color_name || f.color_hex) {
31
+ lines.push('');
32
+ lines.push('## Color');
33
+ if (f.color_name)
34
+ lines.push(`Name: ${f.color_name}`);
35
+ if (f.color_hex)
36
+ lines.push(`Hex: #${f.color_hex}`);
37
+ }
38
+ if (f.finish || f.translucent || f.glow) {
39
+ lines.push('');
40
+ lines.push('## Properties');
41
+ if (f.finish)
42
+ lines.push(`Finish: ${f.finish}`);
43
+ if (f.translucent)
44
+ lines.push('Translucent: Yes');
45
+ if (f.glow)
46
+ lines.push('Glow-in-dark: Yes');
47
+ }
48
+ return lines.join('\n');
49
+ }
50
+ export function registerGetFilament(server, db) {
51
+ server.registerTool('get_filament', {
52
+ title: 'Get Filament',
53
+ description: 'Get detailed information about a specific filament by ID or exact name. Returns full specs: temperatures, density, weight, colors, and manufacturer details.',
54
+ inputSchema: {
55
+ id: z.number().optional().describe('Filament ID'),
56
+ name: z.string().optional().describe('Exact filament name'),
57
+ },
58
+ }, async ({ id, name }) => {
59
+ let filament = null;
60
+ if (id != null) {
61
+ filament = getFilamentById(db, id);
62
+ }
63
+ else if (name != null) {
64
+ filament = getFilamentByName(db, name);
65
+ }
66
+ else {
67
+ return {
68
+ isError: true,
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: 'Please provide either an id or name. Use search_filaments to find filaments first.',
73
+ },
74
+ ],
75
+ };
76
+ }
77
+ if (!filament) {
78
+ return {
79
+ isError: true,
80
+ content: [
81
+ {
82
+ type: 'text',
83
+ text: `Filament not found. Try using search_filaments to find the correct name or ID.`,
84
+ },
85
+ ],
86
+ };
87
+ }
88
+ return {
89
+ content: [
90
+ { type: 'text', text: formatFilamentDetail(filament) },
91
+ ],
92
+ };
93
+ });
94
+ }
95
+ //# sourceMappingURL=get-filament.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-filament.js","sourceRoot":"","sources":["../../src/tools/get-filament.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerGetMaterialProfile(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=get-material-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-material-profile.d.ts","sourceRoot":"","sources":["../../src/tools/get-material-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CA6DN"}
@@ -0,0 +1,57 @@
1
+ import { z } from 'zod';
2
+ import { getMaterialProfile, getAvailableMaterialNames, } from '../data/db.js';
3
+ export function registerGetMaterialProfile(server, db) {
4
+ server.registerTool('get_material_profile', {
5
+ title: 'Get Material Profile',
6
+ description: 'Get a detailed material science profile for a specific material type. Includes strength, flexibility, UV resistance, food safety, moisture sensitivity, difficulty level, typical uses, pros/cons, and nozzle requirements.',
7
+ inputSchema: {
8
+ material: z
9
+ .string()
10
+ .describe('Material type name (e.g., "PLA", "PETG", "ABS", "TPU")'),
11
+ },
12
+ }, async ({ material }) => {
13
+ // Try exact match first, then uppercase
14
+ let profile = getMaterialProfile(db, material);
15
+ if (!profile) {
16
+ profile = getMaterialProfile(db, material.toUpperCase());
17
+ }
18
+ if (!profile) {
19
+ const available = getAvailableMaterialNames(db);
20
+ return {
21
+ isError: true,
22
+ content: [
23
+ {
24
+ type: 'text',
25
+ text: `Material "${material}" not found. Available materials: ${available.join(', ')}`,
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ const lines = [
31
+ `# ${profile.material_name} Material Profile`,
32
+ '',
33
+ '## Temperature Settings',
34
+ `- Print Temperature: ${profile.print_temp_min}-${profile.print_temp_max}°C`,
35
+ `- Bed Temperature: ${profile.bed_temp_min}-${profile.bed_temp_max}°C`,
36
+ '',
37
+ '## Properties',
38
+ `- Strength: ${profile.strength}`,
39
+ `- Flexibility: ${profile.flexibility}`,
40
+ `- UV Resistance: ${profile.uv_resistance}`,
41
+ `- Food Safe: ${profile.food_safe}`,
42
+ `- Moisture Sensitivity: ${profile.moisture_sensitivity}`,
43
+ '',
44
+ '## Printing',
45
+ `- Difficulty: ${profile.difficulty}`,
46
+ `- Nozzle: ${profile.nozzle_notes ?? 'No special requirements'}`,
47
+ `- Enclosure Needed: ${profile.enclosure_needed ? 'Yes' : 'No'}`,
48
+ '',
49
+ '## Usage',
50
+ `- Typical Uses: ${profile.typical_uses}`,
51
+ `- Pros: ${profile.pros}`,
52
+ `- Cons: ${profile.cons}`,
53
+ ];
54
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
55
+ });
56
+ }
57
+ //# sourceMappingURL=get-material-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-material-profile.js","sourceRoot":"","sources":["../../src/tools/get-material-profile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB,MAAM,UAAU,0BAA0B,CACxC,MAAiB,EACjB,EAAqB;IAErB,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,6NAA6N;QAC/N,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,wDAAwD,CAAC;SACtE;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,wCAAwC;QACxC,IAAI,OAAO,GAAG,kBAAkB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,kBAAkB,CAAC,EAAE,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,yBAAyB,CAAC,EAAE,CAAC,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,aAAa,QAAQ,qCAAqC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;qBACvF;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG;YACZ,KAAK,OAAO,CAAC,aAAa,mBAAmB;YAC7C,EAAE;YACF,yBAAyB;YACzB,wBAAwB,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,cAAc,IAAI;YAC5E,sBAAsB,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,IAAI;YACtE,EAAE;YACF,eAAe;YACf,eAAe,OAAO,CAAC,QAAQ,EAAE;YACjC,kBAAkB,OAAO,CAAC,WAAW,EAAE;YACvC,oBAAoB,OAAO,CAAC,aAAa,EAAE;YAC3C,gBAAgB,OAAO,CAAC,SAAS,EAAE;YACnC,2BAA2B,OAAO,CAAC,oBAAoB,EAAE;YACzD,EAAE;YACF,aAAa;YACb,iBAAiB,OAAO,CAAC,UAAU,EAAE;YACrC,aAAa,OAAO,CAAC,YAAY,IAAI,yBAAyB,EAAE;YAChE,uBAAuB,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;YAChE,EAAE;YACF,UAAU;YACV,mBAAmB,OAAO,CAAC,YAAY,EAAE;YACzC,WAAW,OAAO,CAAC,IAAI,EAAE;YACzB,WAAW,OAAO,CAAC,IAAI,EAAE;SAC1B,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerListManufacturers(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=list-manufacturers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-manufacturers.d.ts","sourceRoot":"","sources":["../../src/tools/list-manufacturers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CAyCN"}
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { listManufacturers } from '../data/db.js';
3
+ export function registerListManufacturers(server, db) {
4
+ server.registerTool('list_manufacturers', {
5
+ title: 'List Manufacturers',
6
+ description: 'List all filament manufacturers in the database, with filament counts. Optionally filter to manufacturers that produce a specific material type.',
7
+ inputSchema: {
8
+ material: z
9
+ .string()
10
+ .optional()
11
+ .describe('Filter to manufacturers that produce this material type (e.g., "PLA", "PETG")'),
12
+ },
13
+ }, async ({ material }) => {
14
+ const manufacturers = listManufacturers(db, material);
15
+ const lines = [];
16
+ if (material) {
17
+ lines.push(`${manufacturers.length} manufacturer${manufacturers.length === 1 ? '' : 's'} producing ${material}:\n`);
18
+ }
19
+ else {
20
+ lines.push(`${manufacturers.length} manufacturer${manufacturers.length === 1 ? '' : 's'}:\n`);
21
+ }
22
+ lines.push('| Manufacturer | Filaments |');
23
+ lines.push('|---|---|');
24
+ for (const m of manufacturers) {
25
+ lines.push(`| ${m.name} | ${m.filament_count} |`);
26
+ }
27
+ return {
28
+ content: [{ type: 'text', text: lines.join('\n') }],
29
+ };
30
+ });
31
+ }
32
+ //# sourceMappingURL=list-manufacturers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-manufacturers.js","sourceRoot":"","sources":["../../src/tools/list-manufacturers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,UAAU,yBAAyB,CACvC,MAAiB,EACjB,EAAqB;IAErB,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,kJAAkJ;QACpJ,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,+EAA+E,CAChF;SACJ;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,aAAa,GAAG,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtD,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CACR,GAAG,aAAa,CAAC,MAAM,gBAAgB,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,cAAc,QAAQ,KAAK,CACxG,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CACR,GAAG,aAAa,CAAC,MAAM,gBAAgB,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAClF,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC;QACpD,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerListMaterials(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=list-materials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-materials.d.ts","sourceRoot":"","sources":["../../src/tools/list-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CAmCN"}
@@ -0,0 +1,25 @@
1
+ import { listMaterials } from '../data/db.js';
2
+ export function registerListMaterials(server, db) {
3
+ server.registerTool('list_materials', {
4
+ title: 'List Materials',
5
+ description: 'List all material types available in the database (PLA, PETG, ABS, TPU, Nylon, etc.) with filament counts and typical print settings. No inputs required.',
6
+ }, async () => {
7
+ const materials = listMaterials(db);
8
+ // Sort by count descending
9
+ materials.sort((a, b) => b.filament_count - a.filament_count);
10
+ const lines = [];
11
+ lines.push(`${materials.length} material type${materials.length === 1 ? '' : 's'}:\n`);
12
+ lines.push('| Material | Filaments | Density | Extruder Temp | Bed Temp |');
13
+ lines.push('|---|---|---|---|---|');
14
+ for (const m of materials) {
15
+ const density = m.density != null ? `${m.density} g/cm³` : '-';
16
+ const extruder = m.extruder_temp != null ? `${m.extruder_temp}°C` : '-';
17
+ const bed = m.bed_temp != null ? `${m.bed_temp}°C` : '-';
18
+ lines.push(`| ${m.name} | ${m.filament_count} | ${density} | ${extruder} | ${bed} |`);
19
+ }
20
+ return {
21
+ content: [{ type: 'text', text: lines.join('\n') }],
22
+ };
23
+ });
24
+ }
25
+ //# sourceMappingURL=list-materials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-materials.js","sourceRoot":"","sources":["../../src/tools/list-materials.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,qBAAqB,CACnC,MAAiB,EACjB,EAAqB;IAErB,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EACT,2JAA2J;KAC9J,EACD,KAAK,IAAI,EAAE;QACT,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAEpC,2BAA2B;QAC3B,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;QAE9D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CACR,GAAG,SAAS,CAAC,MAAM,iBAAiB,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAC3E,CAAC;QAEF,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACpC,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;YAC/D,MAAM,QAAQ,GAAG,CAAC,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YACxE,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YACzD,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,cAAc,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAG,IAAI,CAC1E,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SAC7D,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerRecommendMaterial(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=recommend-material.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend-material.d.ts","sourceRoot":"","sources":["../../src/tools/recommend-material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAwE3C,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CA6JN"}
@@ -0,0 +1,195 @@
1
+ import { z } from 'zod';
2
+ import { getAllMaterialProfiles, } from '../data/db.js';
3
+ function scoreStrength(profile, requirement) {
4
+ const strengthMap = {
5
+ low: 1,
6
+ moderate: 2,
7
+ good: 3,
8
+ 'very good': 4,
9
+ excellent: 5,
10
+ };
11
+ const reqMap = { low: 1, medium: 2, high: 4 };
12
+ const actual = strengthMap[profile.strength] ?? 2;
13
+ const required = reqMap[requirement] ?? 2;
14
+ const diff = actual - required;
15
+ if (diff >= 0) {
16
+ return { score: 2, reason: `Strength: ${profile.strength} (meets requirement)` };
17
+ }
18
+ return { score: -1, reason: `Strength: ${profile.strength} (below ${requirement} requirement)` };
19
+ }
20
+ function scoreFoodSafe(profile) {
21
+ const fs = profile.food_safe.toLowerCase();
22
+ if (fs.includes('conditionally') || fs.includes('fda')) {
23
+ return { score: 1, reason: `Food safety: ${profile.food_safe}` };
24
+ }
25
+ return { score: -2, reason: `Not food safe: ${profile.food_safe}` };
26
+ }
27
+ function scoreOutdoor(profile) {
28
+ const uvMap = { poor: -2, low: -1, moderate: 1, good: 2, excellent: 3 };
29
+ const uvScore = uvMap[profile.uv_resistance] ?? 0;
30
+ return {
31
+ score: uvScore,
32
+ reason: `UV resistance: ${profile.uv_resistance}`,
33
+ };
34
+ }
35
+ function scoreEase(profile, requirement) {
36
+ const diffMap = {
37
+ beginner: 1,
38
+ 'beginner-intermediate': 2,
39
+ intermediate: 3,
40
+ 'intermediate-advanced': 4,
41
+ advanced: 5,
42
+ };
43
+ const reqMap = { beginner: 1, intermediate: 3, advanced: 5 };
44
+ const actual = diffMap[profile.difficulty] ?? 3;
45
+ const required = reqMap[requirement] ?? 3;
46
+ if (actual <= required) {
47
+ return { score: 2, reason: `Difficulty: ${profile.difficulty} (within skill level)` };
48
+ }
49
+ return { score: -1, reason: `Difficulty: ${profile.difficulty} (may be challenging for ${requirement})` };
50
+ }
51
+ export function registerRecommendMaterial(server, db) {
52
+ server.registerTool('recommend_material', {
53
+ title: 'Recommend Material',
54
+ 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.',
55
+ inputSchema: {
56
+ requirements: z.object({
57
+ strength: z
58
+ .enum(['low', 'medium', 'high'])
59
+ .optional()
60
+ .describe('Required mechanical strength'),
61
+ flexibility: z
62
+ .enum(['rigid', 'semi-flexible', 'flexible'])
63
+ .optional()
64
+ .describe('Required flexibility'),
65
+ heat_resistance: z
66
+ .enum(['low', 'medium', 'high'])
67
+ .optional()
68
+ .describe('Required heat resistance'),
69
+ food_safe: z
70
+ .boolean()
71
+ .optional()
72
+ .describe('Must be food-safe material'),
73
+ outdoor_use: z
74
+ .boolean()
75
+ .optional()
76
+ .describe('Will be used outdoors (needs UV resistance)'),
77
+ ease_of_printing: z
78
+ .enum(['beginner', 'intermediate', 'advanced'])
79
+ .optional()
80
+ .describe('Desired printing difficulty level'),
81
+ budget: z
82
+ .enum(['low', 'medium', 'high'])
83
+ .optional()
84
+ .describe('Budget constraint'),
85
+ }).describe('Project requirements for material selection'),
86
+ },
87
+ }, async ({ requirements }) => {
88
+ // Check if any requirements provided
89
+ const hasRequirements = Object.values(requirements).some((v) => v !== undefined && v !== null);
90
+ if (!hasRequirements) {
91
+ return {
92
+ isError: true,
93
+ content: [
94
+ {
95
+ type: 'text',
96
+ text: 'Please provide at least one requirement (strength, flexibility, heat_resistance, food_safe, outdoor_use, ease_of_printing, or budget).',
97
+ },
98
+ ],
99
+ };
100
+ }
101
+ const profiles = getAllMaterialProfiles(db);
102
+ const scored = profiles.map((profile) => {
103
+ let score = 0;
104
+ const reasons = [];
105
+ const caveats = [];
106
+ if (requirements.strength) {
107
+ const r = scoreStrength(profile, requirements.strength);
108
+ score += r.score;
109
+ reasons.push(r.reason);
110
+ }
111
+ if (requirements.flexibility) {
112
+ const flexMap = {
113
+ rigid: ['low', 'none'],
114
+ 'semi-flexible': ['moderate', 'medium'],
115
+ flexible: ['high', 'very high', 'flexible'],
116
+ };
117
+ const matches = flexMap[requirements.flexibility] ?? [];
118
+ if (matches.includes(profile.flexibility.toLowerCase())) {
119
+ score += 2;
120
+ reasons.push(`Flexibility: ${profile.flexibility} (matches)`);
121
+ }
122
+ else {
123
+ score -= 1;
124
+ reasons.push(`Flexibility: ${profile.flexibility} (doesn't match ${requirements.flexibility})`);
125
+ }
126
+ }
127
+ if (requirements.heat_resistance) {
128
+ if (requirements.heat_resistance === 'high' && profile.enclosure_needed) {
129
+ score += 2;
130
+ reasons.push('High heat resistance (needs enclosure)');
131
+ }
132
+ else if (requirements.heat_resistance === 'high') {
133
+ score -= 1;
134
+ reasons.push('Limited heat resistance');
135
+ caveats.push(profile.cons);
136
+ }
137
+ else {
138
+ score += 1;
139
+ reasons.push(`Heat resistance: suitable for ${requirements.heat_resistance} needs`);
140
+ }
141
+ }
142
+ if (requirements.food_safe) {
143
+ const r = scoreFoodSafe(profile);
144
+ score += r.score;
145
+ reasons.push(r.reason);
146
+ if (r.score < 0) {
147
+ caveats.push('Not suitable for food contact');
148
+ }
149
+ }
150
+ if (requirements.outdoor_use) {
151
+ const r = scoreOutdoor(profile);
152
+ score += r.score;
153
+ reasons.push(r.reason);
154
+ if (r.score < 0) {
155
+ caveats.push('Poor outdoor durability');
156
+ }
157
+ }
158
+ if (requirements.ease_of_printing) {
159
+ const r = scoreEase(profile, requirements.ease_of_printing);
160
+ score += r.score;
161
+ reasons.push(r.reason);
162
+ }
163
+ if (requirements.budget) {
164
+ if (requirements.budget === 'low' && profile.difficulty === 'beginner') {
165
+ score += 1;
166
+ reasons.push('Budget-friendly (common beginner material)');
167
+ }
168
+ else if (requirements.budget === 'low') {
169
+ score -= 1;
170
+ reasons.push('May be more expensive than basic materials');
171
+ }
172
+ else {
173
+ score += 1;
174
+ reasons.push('Within budget range');
175
+ }
176
+ }
177
+ return { profile, score, reasons, caveats };
178
+ });
179
+ // Sort by score descending
180
+ scored.sort((a, b) => b.score - a.score);
181
+ const lines = ['# Material Recommendations', ''];
182
+ scored.forEach((s, i) => {
183
+ lines.push(`${i + 1}. **${s.profile.material_name}** (score: ${s.score})`);
184
+ for (const reason of s.reasons) {
185
+ lines.push(` - ${reason}`);
186
+ }
187
+ if (s.caveats.length > 0) {
188
+ lines.push(` - Caveats: ${s.caveats.join('; ')}`);
189
+ }
190
+ lines.push('');
191
+ });
192
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
193
+ });
194
+ }
195
+ //# sourceMappingURL=recommend-material.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend-material.js","sourceRoot":"","sources":["../../src/tools/recommend-material.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type Database from 'better-sqlite3';
3
+ export declare function registerSearchFilaments(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=search-filaments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-filaments.d.ts","sourceRoot":"","sources":["../../src/tools/search-filaments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAgC3C,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CA8EN"}