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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/data/3dprint.sqlite +0 -0
- package/dist/data/db.d.ts +88 -0
- package/dist/data/db.d.ts.map +1 -0
- package/dist/data/db.js +175 -0
- package/dist/data/db.js.map +1 -0
- package/dist/data/schema.sql +86 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +58 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/compare-materials.d.ts +4 -0
- package/dist/tools/compare-materials.d.ts.map +1 -0
- package/dist/tools/compare-materials.js +79 -0
- package/dist/tools/compare-materials.js.map +1 -0
- package/dist/tools/diagnose-print-issue.d.ts +4 -0
- package/dist/tools/diagnose-print-issue.d.ts.map +1 -0
- package/dist/tools/diagnose-print-issue.js +58 -0
- package/dist/tools/diagnose-print-issue.js.map +1 -0
- package/dist/tools/get-filament.d.ts +4 -0
- package/dist/tools/get-filament.d.ts.map +1 -0
- package/dist/tools/get-filament.js +95 -0
- package/dist/tools/get-filament.js.map +1 -0
- package/dist/tools/get-material-profile.d.ts +4 -0
- package/dist/tools/get-material-profile.d.ts.map +1 -0
- package/dist/tools/get-material-profile.js +57 -0
- package/dist/tools/get-material-profile.js.map +1 -0
- package/dist/tools/list-manufacturers.d.ts +4 -0
- package/dist/tools/list-manufacturers.d.ts.map +1 -0
- package/dist/tools/list-manufacturers.js +32 -0
- package/dist/tools/list-manufacturers.js.map +1 -0
- package/dist/tools/list-materials.d.ts +4 -0
- package/dist/tools/list-materials.d.ts.map +1 -0
- package/dist/tools/list-materials.js +25 -0
- package/dist/tools/list-materials.js.map +1 -0
- package/dist/tools/recommend-material.d.ts +4 -0
- package/dist/tools/recommend-material.d.ts.map +1 -0
- package/dist/tools/recommend-material.js +195 -0
- package/dist/tools/recommend-material.js.map +1 -0
- package/dist/tools/search-filaments.d.ts +4 -0
- package/dist/tools/search-filaments.d.ts.map +1 -0
- package/dist/tools/search-filaments.js +86 -0
- package/dist/tools/search-filaments.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gregario
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.npmjs.com/package/3dprint-oracle"><img src="https://img.shields.io/npm/v/3dprint-oracle.svg" alt="npm version"></a>
|
|
3
|
+
<a href="https://www.npmjs.com/package/3dprint-oracle"><img src="https://img.shields.io/npm/dm/3dprint-oracle.svg" alt="npm downloads"></a>
|
|
4
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node.js 18+"></a>
|
|
5
|
+
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-compatible-purple.svg" alt="MCP Compatible"></a>
|
|
6
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
7
|
+
<a href="https://github.com/sponsors/gregario"><img src="https://img.shields.io/badge/sponsor-♥-ea4aaa.svg" alt="Sponsor"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
# 3dprint-oracle
|
|
11
|
+
|
|
12
|
+
3D printing filament and materials knowledge MCP server. Gives LLMs authoritative access to 7,000+ filaments and curated material science knowledge.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **7,000+ filaments** from SpoolmanDB (53 manufacturers, 33 material types)
|
|
17
|
+
- **Material science knowledge** — properties, troubleshooting, recommendations
|
|
18
|
+
- **8 MCP tools** — search, lookup, compare, recommend, diagnose
|
|
19
|
+
- **Embedded data** — no API keys, no network calls at runtime
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### Claude Desktop
|
|
24
|
+
|
|
25
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"3dprint-oracle": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "3dprint-oracle"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Tools
|
|
39
|
+
|
|
40
|
+
| Tool | Description |
|
|
41
|
+
|------|-------------|
|
|
42
|
+
| `search_filaments` | Search filaments by name, material, manufacturer, color |
|
|
43
|
+
| `get_filament` | Get full specs for a specific filament |
|
|
44
|
+
| `list_manufacturers` | Browse manufacturers with filament counts |
|
|
45
|
+
| `list_materials` | Browse material types with counts |
|
|
46
|
+
| `get_material_profile` | Authoritative properties for a material type |
|
|
47
|
+
| `compare_materials` | Side-by-side comparison of 2-3 materials |
|
|
48
|
+
| `recommend_material` | Get ranked recommendations for your requirements |
|
|
49
|
+
| `diagnose_print_issue` | Troubleshoot print problems with material-specific fixes |
|
|
50
|
+
|
|
51
|
+
## Data Sources
|
|
52
|
+
|
|
53
|
+
- Filament data: [SpoolmanDB](https://github.com/Donkie/SpoolmanDB) (MIT license)
|
|
54
|
+
- Material knowledge: Hand-curated from authoritative 3D printing references
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT
|
|
Binary file
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
export declare function getDatabase(dataDir?: string): Database.Database;
|
|
3
|
+
export declare function getTableNames(db: Database.Database): string[];
|
|
4
|
+
export interface FilamentRow {
|
|
5
|
+
id: number;
|
|
6
|
+
name: string;
|
|
7
|
+
manufacturer_id: number;
|
|
8
|
+
manufacturer_name: string;
|
|
9
|
+
material_id: number;
|
|
10
|
+
material_name: string;
|
|
11
|
+
density: number | null;
|
|
12
|
+
diameter: number;
|
|
13
|
+
weight: number | null;
|
|
14
|
+
spool_weight: number | null;
|
|
15
|
+
extruder_temp: number | null;
|
|
16
|
+
extruder_temp_min: number | null;
|
|
17
|
+
extruder_temp_max: number | null;
|
|
18
|
+
bed_temp: number | null;
|
|
19
|
+
bed_temp_min: number | null;
|
|
20
|
+
bed_temp_max: number | null;
|
|
21
|
+
color_name: string | null;
|
|
22
|
+
color_hex: string | null;
|
|
23
|
+
finish: string | null;
|
|
24
|
+
translucent: number;
|
|
25
|
+
glow: number;
|
|
26
|
+
}
|
|
27
|
+
export interface SearchFilters {
|
|
28
|
+
material?: string;
|
|
29
|
+
manufacturer?: string;
|
|
30
|
+
diameter?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SearchResult {
|
|
33
|
+
rows: FilamentRow[];
|
|
34
|
+
total: number;
|
|
35
|
+
}
|
|
36
|
+
export declare function searchFilaments(db: Database.Database, query: string, filters?: SearchFilters, limit?: number, offset?: number): SearchResult;
|
|
37
|
+
export declare function getFilamentById(db: Database.Database, id: number): FilamentRow | null;
|
|
38
|
+
export declare function getFilamentByName(db: Database.Database, name: string): FilamentRow | null;
|
|
39
|
+
export interface ManufacturerRow {
|
|
40
|
+
id: number;
|
|
41
|
+
name: string;
|
|
42
|
+
website: string | null;
|
|
43
|
+
country: string | null;
|
|
44
|
+
filament_count: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function listManufacturers(db: Database.Database, materialFilter?: string): ManufacturerRow[];
|
|
47
|
+
export interface MaterialRow {
|
|
48
|
+
id: number;
|
|
49
|
+
name: string;
|
|
50
|
+
density: number | null;
|
|
51
|
+
extruder_temp: number | null;
|
|
52
|
+
bed_temp: number | null;
|
|
53
|
+
filament_count: number;
|
|
54
|
+
}
|
|
55
|
+
export declare function listMaterials(db: Database.Database): MaterialRow[];
|
|
56
|
+
export interface MaterialProfileRow {
|
|
57
|
+
id: number;
|
|
58
|
+
material_name: string;
|
|
59
|
+
print_temp_min: number | null;
|
|
60
|
+
print_temp_max: number | null;
|
|
61
|
+
bed_temp_min: number | null;
|
|
62
|
+
bed_temp_max: number | null;
|
|
63
|
+
strength: string;
|
|
64
|
+
flexibility: string;
|
|
65
|
+
uv_resistance: string;
|
|
66
|
+
food_safe: string;
|
|
67
|
+
moisture_sensitivity: string;
|
|
68
|
+
difficulty: string;
|
|
69
|
+
typical_uses: string;
|
|
70
|
+
pros: string;
|
|
71
|
+
cons: string;
|
|
72
|
+
nozzle_notes: string | null;
|
|
73
|
+
enclosure_needed: number;
|
|
74
|
+
}
|
|
75
|
+
export declare function getMaterialProfile(db: Database.Database, name: string): MaterialProfileRow | null;
|
|
76
|
+
export declare function getAllMaterialProfiles(db: Database.Database): MaterialProfileRow[];
|
|
77
|
+
export interface TroubleshootingRow {
|
|
78
|
+
id: number;
|
|
79
|
+
symptom: string;
|
|
80
|
+
material_name: string | null;
|
|
81
|
+
cause: string;
|
|
82
|
+
fix: string;
|
|
83
|
+
probability: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function getTroubleshooting(db: Database.Database, symptom: string, material?: string): TroubleshootingRow[];
|
|
86
|
+
export declare function getAvailableSymptoms(db: Database.Database): string[];
|
|
87
|
+
export declare function getAvailableMaterialNames(db: Database.Database): string[];
|
|
88
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/data/db.ts"],"names":[],"mappings":"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"}
|
package/dist/data/db.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const DB_FILENAME = '3dprint.sqlite';
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const SCHEMA_PATH = path.join(__dirname, 'schema.sql');
|
|
8
|
+
export function getDatabase(dataDir) {
|
|
9
|
+
let db;
|
|
10
|
+
if (dataDir === ':memory:') {
|
|
11
|
+
db = new Database(':memory:');
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const dir = dataDir ?? __dirname;
|
|
15
|
+
const dbPath = dir.endsWith('.sqlite') ? dir : path.join(dir, DB_FILENAME);
|
|
16
|
+
const parentDir = path.dirname(dbPath);
|
|
17
|
+
if (!fs.existsSync(parentDir)) {
|
|
18
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
db = new Database(dbPath);
|
|
21
|
+
}
|
|
22
|
+
db.pragma('journal_mode = WAL');
|
|
23
|
+
db.pragma('foreign_keys = ON');
|
|
24
|
+
initializeSchema(db);
|
|
25
|
+
return db;
|
|
26
|
+
}
|
|
27
|
+
function initializeSchema(db) {
|
|
28
|
+
const schema = fs.readFileSync(SCHEMA_PATH, 'utf-8');
|
|
29
|
+
db.exec(schema);
|
|
30
|
+
}
|
|
31
|
+
export function getTableNames(db) {
|
|
32
|
+
const rows = db
|
|
33
|
+
.prepare("SELECT name FROM sqlite_master WHERE type IN ('table', 'trigger') AND name NOT LIKE 'sqlite_%' ORDER BY name")
|
|
34
|
+
.all();
|
|
35
|
+
return rows.map((r) => r.name);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sanitize a query string for FTS5 MATCH — escape special characters.
|
|
39
|
+
*/
|
|
40
|
+
function sanitizeFtsQuery(query) {
|
|
41
|
+
// Remove FTS5 special chars: " * ^ ( ) { } [ ] + - ~ : OR AND NOT
|
|
42
|
+
return query.replace(/["\*\^\(\)\{\}\[\]\+\-~:]/g, ' ').trim();
|
|
43
|
+
}
|
|
44
|
+
const FILAMENT_BASE_SELECT = `
|
|
45
|
+
SELECT f.*, m.name AS manufacturer_name
|
|
46
|
+
FROM filaments f
|
|
47
|
+
JOIN manufacturers m ON f.manufacturer_id = m.id
|
|
48
|
+
`;
|
|
49
|
+
export function searchFilaments(db, query, filters = {}, limit = 20, offset = 0) {
|
|
50
|
+
const conditions = [];
|
|
51
|
+
const params = [];
|
|
52
|
+
// FTS match
|
|
53
|
+
const sanitized = sanitizeFtsQuery(query);
|
|
54
|
+
if (sanitized.length > 0) {
|
|
55
|
+
// Add wildcard suffix for prefix matching
|
|
56
|
+
const ftsTerms = sanitized
|
|
57
|
+
.split(/\s+/)
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.map((t) => `"${t}"*`)
|
|
60
|
+
.join(' ');
|
|
61
|
+
conditions.push('f.id IN (SELECT rowid FROM filaments_fts WHERE filaments_fts MATCH ?)');
|
|
62
|
+
params.push(ftsTerms);
|
|
63
|
+
}
|
|
64
|
+
// Filters
|
|
65
|
+
if (filters.material) {
|
|
66
|
+
conditions.push('f.material_name = ?');
|
|
67
|
+
params.push(filters.material);
|
|
68
|
+
}
|
|
69
|
+
if (filters.manufacturer) {
|
|
70
|
+
conditions.push('m.name = ?');
|
|
71
|
+
params.push(filters.manufacturer);
|
|
72
|
+
}
|
|
73
|
+
if (filters.diameter) {
|
|
74
|
+
conditions.push('f.diameter = ?');
|
|
75
|
+
params.push(filters.diameter);
|
|
76
|
+
}
|
|
77
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
78
|
+
// Total count
|
|
79
|
+
const countSql = `
|
|
80
|
+
SELECT COUNT(*) AS cnt
|
|
81
|
+
FROM filaments f
|
|
82
|
+
JOIN manufacturers m ON f.manufacturer_id = m.id
|
|
83
|
+
${where}
|
|
84
|
+
`;
|
|
85
|
+
const { cnt } = db.prepare(countSql).get(...params);
|
|
86
|
+
// Page of results
|
|
87
|
+
const dataSql = `
|
|
88
|
+
${FILAMENT_BASE_SELECT}
|
|
89
|
+
${where}
|
|
90
|
+
ORDER BY f.name
|
|
91
|
+
LIMIT ? OFFSET ?
|
|
92
|
+
`;
|
|
93
|
+
const rows = db
|
|
94
|
+
.prepare(dataSql)
|
|
95
|
+
.all(...params, limit, offset);
|
|
96
|
+
return { rows, total: cnt };
|
|
97
|
+
}
|
|
98
|
+
export function getFilamentById(db, id) {
|
|
99
|
+
const row = db
|
|
100
|
+
.prepare(`${FILAMENT_BASE_SELECT} WHERE f.id = ?`)
|
|
101
|
+
.get(id);
|
|
102
|
+
return row ?? null;
|
|
103
|
+
}
|
|
104
|
+
export function getFilamentByName(db, name) {
|
|
105
|
+
const row = db
|
|
106
|
+
.prepare(`${FILAMENT_BASE_SELECT} WHERE f.name = ?`)
|
|
107
|
+
.get(name);
|
|
108
|
+
return row ?? null;
|
|
109
|
+
}
|
|
110
|
+
export function listManufacturers(db, materialFilter) {
|
|
111
|
+
if (materialFilter) {
|
|
112
|
+
return db
|
|
113
|
+
.prepare(`SELECT m.*, COUNT(f.id) AS filament_count
|
|
114
|
+
FROM manufacturers m
|
|
115
|
+
JOIN filaments f ON f.manufacturer_id = m.id
|
|
116
|
+
WHERE f.material_name = ?
|
|
117
|
+
GROUP BY m.id
|
|
118
|
+
ORDER BY m.name`)
|
|
119
|
+
.all(materialFilter);
|
|
120
|
+
}
|
|
121
|
+
return db
|
|
122
|
+
.prepare(`SELECT m.*, COUNT(f.id) AS filament_count
|
|
123
|
+
FROM manufacturers m
|
|
124
|
+
JOIN filaments f ON f.manufacturer_id = m.id
|
|
125
|
+
GROUP BY m.id
|
|
126
|
+
ORDER BY m.name`)
|
|
127
|
+
.all();
|
|
128
|
+
}
|
|
129
|
+
export function listMaterials(db) {
|
|
130
|
+
return db
|
|
131
|
+
.prepare(`SELECT mat.*, COUNT(f.id) AS filament_count
|
|
132
|
+
FROM materials mat
|
|
133
|
+
JOIN filaments f ON f.material_id = mat.id
|
|
134
|
+
GROUP BY mat.id
|
|
135
|
+
ORDER BY mat.name`)
|
|
136
|
+
.all();
|
|
137
|
+
}
|
|
138
|
+
export function getMaterialProfile(db, name) {
|
|
139
|
+
const row = db
|
|
140
|
+
.prepare('SELECT * FROM material_profiles WHERE material_name = ?')
|
|
141
|
+
.get(name);
|
|
142
|
+
return row ?? null;
|
|
143
|
+
}
|
|
144
|
+
export function getAllMaterialProfiles(db) {
|
|
145
|
+
return db
|
|
146
|
+
.prepare('SELECT * FROM material_profiles ORDER BY material_name')
|
|
147
|
+
.all();
|
|
148
|
+
}
|
|
149
|
+
export function getTroubleshooting(db, symptom, material) {
|
|
150
|
+
if (material) {
|
|
151
|
+
return db
|
|
152
|
+
.prepare(`SELECT * FROM troubleshooting
|
|
153
|
+
WHERE symptom = ? AND (material_name = ? OR material_name IS NULL)
|
|
154
|
+
ORDER BY probability DESC`)
|
|
155
|
+
.all(symptom, material);
|
|
156
|
+
}
|
|
157
|
+
return db
|
|
158
|
+
.prepare(`SELECT * FROM troubleshooting
|
|
159
|
+
WHERE symptom = ?
|
|
160
|
+
ORDER BY probability DESC`)
|
|
161
|
+
.all(symptom);
|
|
162
|
+
}
|
|
163
|
+
export function getAvailableSymptoms(db) {
|
|
164
|
+
const rows = db
|
|
165
|
+
.prepare('SELECT DISTINCT symptom FROM troubleshooting ORDER BY symptom')
|
|
166
|
+
.all();
|
|
167
|
+
return rows.map((r) => r.symptom);
|
|
168
|
+
}
|
|
169
|
+
export function getAvailableMaterialNames(db) {
|
|
170
|
+
const rows = db
|
|
171
|
+
.prepare('SELECT DISTINCT material_name FROM material_profiles ORDER BY material_name')
|
|
172
|
+
.all();
|
|
173
|
+
return rows.map((r) => r.material_name);
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/data/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
-- Manufacturers
|
|
2
|
+
CREATE TABLE IF NOT EXISTS manufacturers (
|
|
3
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
name TEXT NOT NULL UNIQUE,
|
|
5
|
+
website TEXT,
|
|
6
|
+
country TEXT
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
-- Materials (from SpoolmanDB materials.json)
|
|
10
|
+
CREATE TABLE IF NOT EXISTS materials (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
name TEXT NOT NULL UNIQUE,
|
|
13
|
+
density REAL,
|
|
14
|
+
extruder_temp INTEGER,
|
|
15
|
+
bed_temp INTEGER
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
-- Filaments (expanded: one row per filament x color x diameter x weight combo)
|
|
19
|
+
CREATE TABLE IF NOT EXISTS filaments (
|
|
20
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
+
name TEXT NOT NULL,
|
|
22
|
+
manufacturer_id INTEGER NOT NULL REFERENCES manufacturers(id),
|
|
23
|
+
material_id INTEGER NOT NULL REFERENCES materials(id),
|
|
24
|
+
material_name TEXT NOT NULL,
|
|
25
|
+
density REAL,
|
|
26
|
+
diameter REAL NOT NULL,
|
|
27
|
+
weight REAL,
|
|
28
|
+
spool_weight REAL,
|
|
29
|
+
extruder_temp INTEGER,
|
|
30
|
+
extruder_temp_min INTEGER,
|
|
31
|
+
extruder_temp_max INTEGER,
|
|
32
|
+
bed_temp INTEGER,
|
|
33
|
+
bed_temp_min INTEGER,
|
|
34
|
+
bed_temp_max INTEGER,
|
|
35
|
+
color_name TEXT,
|
|
36
|
+
color_hex TEXT,
|
|
37
|
+
finish TEXT,
|
|
38
|
+
translucent INTEGER DEFAULT 0,
|
|
39
|
+
glow INTEGER DEFAULT 0
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
-- FTS5 for filament search
|
|
43
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS filaments_fts USING fts5(
|
|
44
|
+
name,
|
|
45
|
+
color_name,
|
|
46
|
+
content='filaments',
|
|
47
|
+
content_rowid='id',
|
|
48
|
+
tokenize='porter unicode61'
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
-- Triggers to keep FTS in sync
|
|
52
|
+
CREATE TRIGGER IF NOT EXISTS filaments_ai AFTER INSERT ON filaments BEGIN
|
|
53
|
+
INSERT INTO filaments_fts(rowid, name, color_name)
|
|
54
|
+
VALUES (new.id, new.name, new.color_name);
|
|
55
|
+
END;
|
|
56
|
+
|
|
57
|
+
-- Material profiles (curated knowledge layer)
|
|
58
|
+
CREATE TABLE IF NOT EXISTS material_profiles (
|
|
59
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
60
|
+
material_name TEXT NOT NULL UNIQUE,
|
|
61
|
+
print_temp_min INTEGER,
|
|
62
|
+
print_temp_max INTEGER,
|
|
63
|
+
bed_temp_min INTEGER,
|
|
64
|
+
bed_temp_max INTEGER,
|
|
65
|
+
strength TEXT NOT NULL,
|
|
66
|
+
flexibility TEXT NOT NULL,
|
|
67
|
+
uv_resistance TEXT NOT NULL,
|
|
68
|
+
food_safe TEXT NOT NULL,
|
|
69
|
+
moisture_sensitivity TEXT NOT NULL,
|
|
70
|
+
difficulty TEXT NOT NULL,
|
|
71
|
+
typical_uses TEXT NOT NULL,
|
|
72
|
+
pros TEXT NOT NULL,
|
|
73
|
+
cons TEXT NOT NULL,
|
|
74
|
+
nozzle_notes TEXT,
|
|
75
|
+
enclosure_needed INTEGER DEFAULT 0
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
-- Troubleshooting (curated knowledge layer)
|
|
79
|
+
CREATE TABLE IF NOT EXISTS troubleshooting (
|
|
80
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
81
|
+
symptom TEXT NOT NULL,
|
|
82
|
+
material_name TEXT,
|
|
83
|
+
cause TEXT NOT NULL,
|
|
84
|
+
fix TEXT NOT NULL,
|
|
85
|
+
probability TEXT NOT NULL DEFAULT 'medium'
|
|
86
|
+
);
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
export interface ServerOptions {
|
|
4
|
+
dbPath?: string;
|
|
5
|
+
db?: import('better-sqlite3').Database;
|
|
6
|
+
}
|
|
7
|
+
export declare function createServer(options?: ServerOptions): McpServer;
|
|
8
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgBpE,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,gBAAgB,EAAE,QAAQ,CAAC;CACxC;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CA6B/D"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { getDatabase } from './data/db.js';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { registerSearchFilaments } from './tools/search-filaments.js';
|
|
9
|
+
import { registerGetFilament } from './tools/get-filament.js';
|
|
10
|
+
import { registerListManufacturers } from './tools/list-manufacturers.js';
|
|
11
|
+
import { registerListMaterials } from './tools/list-materials.js';
|
|
12
|
+
import { registerGetMaterialProfile } from './tools/get-material-profile.js';
|
|
13
|
+
import { registerCompareMaterials } from './tools/compare-materials.js';
|
|
14
|
+
import { registerRecommendMaterial } from './tools/recommend-material.js';
|
|
15
|
+
import { registerDiagnosePrintIssue } from './tools/diagnose-print-issue.js';
|
|
16
|
+
export function createServer(options) {
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
let version = '0.0.0';
|
|
19
|
+
try {
|
|
20
|
+
const pkg = JSON.parse(readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
21
|
+
version = pkg.version;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Fallback version if package.json not found (e.g., in tests)
|
|
25
|
+
}
|
|
26
|
+
const server = new McpServer({
|
|
27
|
+
name: '3dprint-oracle',
|
|
28
|
+
version,
|
|
29
|
+
});
|
|
30
|
+
const db = options?.db ?? getDatabase(options?.dbPath);
|
|
31
|
+
registerSearchFilaments(server, db);
|
|
32
|
+
registerGetFilament(server, db);
|
|
33
|
+
registerListManufacturers(server, db);
|
|
34
|
+
registerListMaterials(server, db);
|
|
35
|
+
registerGetMaterialProfile(server, db);
|
|
36
|
+
registerCompareMaterials(server, db);
|
|
37
|
+
registerRecommendMaterial(server, db);
|
|
38
|
+
registerDiagnosePrintIssue(server, db);
|
|
39
|
+
return server;
|
|
40
|
+
}
|
|
41
|
+
// Only start stdio when run directly
|
|
42
|
+
const isMain = process.argv[1] &&
|
|
43
|
+
fileURLToPath(import.meta.url).includes(process.argv[1]);
|
|
44
|
+
if (isMain) {
|
|
45
|
+
console.error('3dprint-oracle MCP server starting...');
|
|
46
|
+
const server = createServer();
|
|
47
|
+
const transport = new StdioServerTransport();
|
|
48
|
+
await server.connect(transport);
|
|
49
|
+
process.on('SIGINT', async () => {
|
|
50
|
+
await server.close();
|
|
51
|
+
process.exit(0);
|
|
52
|
+
});
|
|
53
|
+
process.on('SIGTERM', async () => {
|
|
54
|
+
await server.close();
|
|
55
|
+
process.exit(0);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-materials.d.ts","sourceRoot":"","sources":["../../src/tools/compare-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAQ3C,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,IAAI,CA4FN"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getMaterialProfile, getAvailableMaterialNames, } from '../data/db.js';
|
|
3
|
+
export function registerCompareMaterials(server, db) {
|
|
4
|
+
server.registerTool('compare_materials', {
|
|
5
|
+
title: 'Compare Materials',
|
|
6
|
+
description: 'Compare 2-3 material types side by side across all properties: strength, flexibility, heat resistance, food safety, print difficulty, and more. Useful for deciding which material to use for a project.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
materials: z
|
|
9
|
+
.array(z.string())
|
|
10
|
+
.min(2)
|
|
11
|
+
.max(3)
|
|
12
|
+
.describe('Array of 2-3 material type names to compare (e.g., ["PLA", "PETG", "ABS"])'),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ materials }) => {
|
|
15
|
+
const profiles = [];
|
|
16
|
+
for (const name of materials) {
|
|
17
|
+
let profile = getMaterialProfile(db, name);
|
|
18
|
+
if (!profile) {
|
|
19
|
+
profile = getMaterialProfile(db, name.toUpperCase());
|
|
20
|
+
}
|
|
21
|
+
if (!profile) {
|
|
22
|
+
return {
|
|
23
|
+
isError: true,
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: `Material "${name}" not found. Cannot compare. Available materials: ${getAvailableMaterialNames(db).join(', ')}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
profiles.push(profile);
|
|
33
|
+
}
|
|
34
|
+
const names = profiles.map((p) => p.material_name);
|
|
35
|
+
const header = `# Material Comparison: ${names.join(' vs ')}\n`;
|
|
36
|
+
const properties = [
|
|
37
|
+
{ label: 'Print Temp', getter: (p) => `${p.print_temp_min}-${p.print_temp_max}°C` },
|
|
38
|
+
{ label: 'Bed Temp', getter: (p) => `${p.bed_temp_min}-${p.bed_temp_max}°C` },
|
|
39
|
+
{ label: 'Strength', getter: (p) => p.strength },
|
|
40
|
+
{ label: 'Flexibility', getter: (p) => p.flexibility },
|
|
41
|
+
{ label: 'UV Resistance', getter: (p) => p.uv_resistance },
|
|
42
|
+
{ label: 'Food Safe', getter: (p) => p.food_safe },
|
|
43
|
+
{ label: 'Moisture Sensitivity', getter: (p) => p.moisture_sensitivity },
|
|
44
|
+
{ label: 'Difficulty', getter: (p) => p.difficulty },
|
|
45
|
+
{ label: 'Enclosure Needed', getter: (p) => p.enclosure_needed ? 'Yes' : 'No' },
|
|
46
|
+
{ label: 'Nozzle', getter: (p) => p.nozzle_notes ?? 'Standard' },
|
|
47
|
+
];
|
|
48
|
+
// Build table
|
|
49
|
+
const colWidth = 25;
|
|
50
|
+
const labelWidth = 22;
|
|
51
|
+
const separator = '-'.repeat(labelWidth + colWidth * names.length + names.length + 1);
|
|
52
|
+
let table = `| ${'Property'.padEnd(labelWidth)}|`;
|
|
53
|
+
for (const name of names) {
|
|
54
|
+
table += ` ${name.padEnd(colWidth - 1)}|`;
|
|
55
|
+
}
|
|
56
|
+
table += '\n' + separator + '\n';
|
|
57
|
+
for (const prop of properties) {
|
|
58
|
+
let row = `| ${prop.label.padEnd(labelWidth)}|`;
|
|
59
|
+
for (const profile of profiles) {
|
|
60
|
+
const val = prop.getter(profile);
|
|
61
|
+
row += ` ${val.substring(0, colWidth - 2).padEnd(colWidth - 1)}|`;
|
|
62
|
+
}
|
|
63
|
+
table += row + '\n';
|
|
64
|
+
}
|
|
65
|
+
// When to use summary
|
|
66
|
+
const whenToUse = profiles
|
|
67
|
+
.map((p) => `- **${p.material_name}**: ${p.typical_uses} (${p.pros})`)
|
|
68
|
+
.join('\n');
|
|
69
|
+
const text = [
|
|
70
|
+
header,
|
|
71
|
+
table,
|
|
72
|
+
'',
|
|
73
|
+
'## When to use each',
|
|
74
|
+
whenToUse,
|
|
75
|
+
].join('\n');
|
|
76
|
+
return { content: [{ type: 'text', text }] };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=compare-materials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-materials.js","sourceRoot":"","sources":["../../src/tools/compare-materials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose-print-issue.d.ts","sourceRoot":"","sources":["../../src/tools/diagnose-print-issue.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,CAmEN"}
|