@sealab/mcp-server 1.0.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 (48) hide show
  1. package/PROPOSED-CHANGES-INSERTION-POINTS.md +220 -0
  2. package/SEALAB_MCP_DOCUMENTATION.md +1136 -0
  3. package/dist/client/api-client.js +44 -0
  4. package/dist/index.js +42 -0
  5. package/dist/tools/canvas.js +446 -0
  6. package/dist/tools/catalog.js +95 -0
  7. package/dist/tools/configuration-info.js +299 -0
  8. package/dist/tools/configuration.js +32 -0
  9. package/dist/tools/orders.js +1267 -0
  10. package/dist/tools/saved-settings.js +271 -0
  11. package/package.json +32 -0
  12. package/resources/tooltips/backPanel.txt +17 -0
  13. package/resources/tooltips/backPanelMaterial.txt +29 -0
  14. package/resources/tooltips/caseEdge.txt +18 -0
  15. package/resources/tooltips/caseMaterial.txt +31 -0
  16. package/resources/tooltips/depth.txt +11 -0
  17. package/resources/tooltips/drawerType.txt +12 -0
  18. package/resources/tooltips/edgeBandingType.txt +18 -0
  19. package/resources/tooltips/excludeFronts.txt +5 -0
  20. package/resources/tooltips/frontEdge.txt +18 -0
  21. package/resources/tooltips/frontMaterial.txt +35 -0
  22. package/resources/tooltips/gapBottom.txt +2 -0
  23. package/resources/tooltips/gapCenter.txt +2 -0
  24. package/resources/tooltips/gapLeft.txt +15 -0
  25. package/resources/tooltips/gapRight.txt +15 -0
  26. package/resources/tooltips/gapTop.txt +2 -0
  27. package/resources/tooltips/height.txt +6 -0
  28. package/resources/tooltips/hingePlate.txt +11 -0
  29. package/resources/tooltips/includeLegLevelers.txt +8 -0
  30. package/resources/tooltips/jointMethod.txt +7 -0
  31. package/resources/tooltips/leftCornerWidth.txt +2 -0
  32. package/resources/tooltips/numOfShelves.txt +6 -0
  33. package/resources/tooltips/positionName.txt +3 -0
  34. package/resources/tooltips/rightCornerDepth.txt +2 -0
  35. package/resources/tooltips/topDrwrHeight.txt +8 -0
  36. package/resources/tooltips/width.txt +5 -0
  37. package/src/client/api-client.ts +37 -0
  38. package/src/index.ts +52 -0
  39. package/src/tools/canvas.ts +442 -0
  40. package/src/tools/catalog.test.ts +61 -0
  41. package/src/tools/catalog.ts +80 -0
  42. package/src/tools/configuration-info.ts +274 -0
  43. package/src/tools/configuration.test.ts +43 -0
  44. package/src/tools/configuration.ts +25 -0
  45. package/src/tools/orders.test.ts +260 -0
  46. package/src/tools/orders.ts +1229 -0
  47. package/src/tools/saved-settings.ts +241 -0
  48. package/tsconfig.json +15 -0
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.configurationInfoTools = void 0;
37
+ exports.getArticleContext = getArticleContext;
38
+ exports.getArticleOptions = getArticleOptions;
39
+ exports.getConfigurationInfo = getConfigurationInfo;
40
+ const zod_1 = require("zod");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const api_client_1 = require("../client/api-client");
44
+ // All fields with a corresponding .txt file in resources/tooltips/
45
+ const VALID_FIELDS = [
46
+ 'backPanel',
47
+ 'backPanelMaterial',
48
+ 'caseEdge',
49
+ 'caseMaterial',
50
+ 'depth',
51
+ 'drawerType',
52
+ 'edgeBandingType',
53
+ 'excludeFronts',
54
+ 'frontEdge',
55
+ 'frontMaterial',
56
+ 'gapBottom',
57
+ 'gapCenter',
58
+ 'gapLeft',
59
+ 'gapRight',
60
+ 'gapTop',
61
+ 'height',
62
+ 'hingePlate',
63
+ 'includeLegLevelers',
64
+ 'jointMethod',
65
+ 'leftCornerWidth',
66
+ 'numOfShelves',
67
+ 'positionName',
68
+ 'rightCornerDepth',
69
+ 'topDrwrHeight',
70
+ 'width',
71
+ ];
72
+ const SerialNumberSchema = zod_1.z.object({
73
+ serialNumber: zod_1.z.string().describe('Article serial number'),
74
+ });
75
+ const GetArticleContextSchema = SerialNumberSchema;
76
+ const GetArticleOptionsSchema = SerialNumberSchema;
77
+ const GetConfigInfoSchema = zod_1.z.object({
78
+ field: zod_1.z.enum(VALID_FIELDS).describe('The configuration field name to get full detail for'),
79
+ });
80
+ // ---------------------------------------------------------------------------
81
+ // Helpers
82
+ // ---------------------------------------------------------------------------
83
+ /** Strip HTML tags and collapse whitespace for clean plain-text output */
84
+ function stripHtml(html) {
85
+ return html
86
+ .replace(/<[^>]*>/g, ' ')
87
+ .replace(/&nbsp;/g, ' ')
88
+ .replace(/&amp;/g, '&')
89
+ .replace(/&lt;/g, '<')
90
+ .replace(/&gt;/g, '>')
91
+ .replace(/&quot;/g, '"')
92
+ .replace(/\s+/g, ' ')
93
+ .trim();
94
+ }
95
+ /** Read a tooltip file, returns null if missing */
96
+ function readTooltip(field) {
97
+ const filePath = path.join(__dirname, '..', '..', 'resources', 'tooltips', `${field}.txt`);
98
+ try {
99
+ return stripHtml(fs.readFileSync(filePath, 'utf-8'));
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ /** Derive the list of applicable config fields from the configuration response */
106
+ function getApplicableFields(config) {
107
+ const fields = ['positionName', 'height', 'width', 'depth'];
108
+ if (config.hasCase === true)
109
+ fields.push('caseMaterial');
110
+ if (config.hasMatCaseThin === true)
111
+ fields.push('caseMaterial'); // inner — same file
112
+ if (config.hasFront === true)
113
+ fields.push('frontMaterial');
114
+ if (config.hasCase === true && config.hasFront === true)
115
+ fields.push('excludeFronts');
116
+ if (config.matBack === true)
117
+ fields.push('backPanelMaterial', 'backPanel');
118
+ if (config.caseEdge === true)
119
+ fields.push('caseEdge');
120
+ if (config.frontEdge === true)
121
+ fields.push('frontEdge');
122
+ if (config.doors === true)
123
+ fields.push('hingePlate');
124
+ if (config.drawers === true)
125
+ fields.push('drawerType');
126
+ if (config.topDrwrHeight === true)
127
+ fields.push('topDrwrHeight');
128
+ if (config.adjShelves === true)
129
+ fields.push('numOfShelves');
130
+ if (config.gapControl === true)
131
+ fields.push('gapTop', 'gapBottom', 'gapLeft', 'gapRight', 'gapCenter');
132
+ if (config.jointControl === true)
133
+ fields.push('jointMethod');
134
+ if (config.cornerVariables === true)
135
+ fields.push('leftCornerWidth', 'rightCornerDepth');
136
+ // LP_SP / LP_GP series use edgeBandingType instead of standard edge fields
137
+ const sn = config.serialNumber ?? '';
138
+ if (sn.startsWith('LP_SP') || sn.startsWith('LP_GP'))
139
+ fields.push('edgeBandingType');
140
+ // Leg levelers: filterTags-based (dimension check happens at order time)
141
+ const tags = config.filterTags ?? '';
142
+ if (tags.includes('Leg_Levelers'))
143
+ fields.push('includeLegLevelers');
144
+ // Deduplicate while preserving order
145
+ return [...new Set(fields)];
146
+ }
147
+ // ---------------------------------------------------------------------------
148
+ // Tool: get_article_context
149
+ // ---------------------------------------------------------------------------
150
+ async function getArticleContext(input) {
151
+ try {
152
+ const { data: config } = await api_client_1.client.get(`/catalog/${input.serialNumber}/configuration`);
153
+ const applicable = getApplicableFields(config);
154
+ const lines = [];
155
+ lines.push(`=== CONFIGURATION CONTEXT: ${input.serialNumber} ===`);
156
+ lines.push('');
157
+ lines.push('DIMENSION RANGES:');
158
+ lines.push(` height: ${config.heightRange ?? 'fixed'}`);
159
+ lines.push(` width: ${config.widthRange ?? 'fixed'}`);
160
+ lines.push(` depth: ${config.depthRange ?? 'fixed'}`);
161
+ lines.push('');
162
+ lines.push(`APPLICABLE CONFIG OPTIONS (${applicable.length - 3} fields beyond dimensions):`);
163
+ lines.push('');
164
+ for (const field of applicable) {
165
+ const content = readTooltip(field);
166
+ if (content) {
167
+ lines.push(`[${field}]`);
168
+ lines.push(content);
169
+ lines.push('');
170
+ }
171
+ }
172
+ lines.push('---');
173
+ lines.push('INSTRUCTIONS:');
174
+ lines.push('1. Present a brief summary of each applicable option to the user.');
175
+ lines.push('2. For every option that applies to this article, ASK the user what they want — do NOT auto-select, guess, or assume any value.');
176
+ lines.push('3. Only move to create_order once the user has explicitly confirmed a value for every applicable field.');
177
+ lines.push('4. If the user provides a drawing or spec that does not specify a value (e.g. no material called out), treat it as missing and ask.');
178
+ lines.push('5. Only call get_configuration_info if the user asks for more detail on a specific field.');
179
+ return lines.join('\n');
180
+ }
181
+ catch (error) {
182
+ try {
183
+ (0, api_client_1.handleAxiosError)(error);
184
+ }
185
+ catch (e) {
186
+ return e.message;
187
+ }
188
+ return 'Unexpected error loading article context.';
189
+ }
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // Tool: get_article_options
193
+ // ---------------------------------------------------------------------------
194
+ async function getArticleOptions(input) {
195
+ try {
196
+ const { data } = await api_client_1.client.get(`/catalog/${input.serialNumber}/options`);
197
+ if (!data || Object.keys(data).length === 0) {
198
+ return 'No selectable options found for this article.';
199
+ }
200
+ const lines = [];
201
+ lines.push(`=== SELECTABLE OPTIONS: ${input.serialNumber} ===`);
202
+ lines.push('');
203
+ lines.push('Use these exact strings when setting field values in create_order.');
204
+ lines.push('');
205
+ if (data.materials) {
206
+ lines.push('MATERIALS (caseMaterial / frontMaterial / backPanelMaterial / innerCaseMaterial):');
207
+ data.materials.forEach((m) => lines.push(` - ${m}`));
208
+ lines.push('');
209
+ }
210
+ if (data.edgebanding) {
211
+ lines.push('EDGEBANDING (caseEdge / frontEdge):');
212
+ data.edgebanding.forEach((e) => lines.push(` - ${e}`));
213
+ lines.push('');
214
+ }
215
+ if (data.jointMethod) {
216
+ lines.push('JOINT METHOD (jointMethod):');
217
+ data.jointMethod.forEach((v) => lines.push(` - ${v}`));
218
+ lines.push('');
219
+ }
220
+ if (data.drawerType) {
221
+ lines.push('DRAWER TYPE (drawerType):');
222
+ data.drawerType.forEach((v) => lines.push(` - ${v}`));
223
+ lines.push('');
224
+ }
225
+ if (data.hingePlate) {
226
+ lines.push('HINGE PLATE (hingePlate):');
227
+ data.hingePlate.forEach((v) => lines.push(` - ${v}`));
228
+ lines.push('');
229
+ }
230
+ if (data.backPanel) {
231
+ lines.push('BACK PANEL METHOD (backPanel):');
232
+ data.backPanel.forEach((v) => lines.push(` - ${v}`));
233
+ lines.push('');
234
+ }
235
+ if (data.numOfShelves) {
236
+ lines.push('NUMBER OF ADJUSTABLE SHELVES (numOfShelves):');
237
+ lines.push(` - ${data.numOfShelves.join(', ')}`);
238
+ lines.push('');
239
+ }
240
+ return lines.join('\n');
241
+ }
242
+ catch (error) {
243
+ try {
244
+ (0, api_client_1.handleAxiosError)(error);
245
+ }
246
+ catch (e) {
247
+ return e.message;
248
+ }
249
+ return 'Unexpected error loading article options.';
250
+ }
251
+ }
252
+ // ---------------------------------------------------------------------------
253
+ // Tool: get_configuration_info (single-field deep dive)
254
+ // ---------------------------------------------------------------------------
255
+ async function getConfigurationInfo(input) {
256
+ const content = readTooltip(input.field);
257
+ return content ?? `No information available for field: ${input.field}`;
258
+ }
259
+ // ---------------------------------------------------------------------------
260
+ // Exports
261
+ // ---------------------------------------------------------------------------
262
+ exports.configurationInfoTools = [
263
+ {
264
+ name: 'get_article_options',
265
+ description: `Fetch the valid selectable values for all applicable configuration fields for a cabinet article. Returns the exact strings to use when setting caseMaterial, frontMaterial, backPanelMaterial, innerCaseMaterial, caseEdge, frontEdge, jointMethod, drawerType, hingePlate, backPanel, and numOfShelves in create_order.
266
+
267
+ Call this immediately after get_article_context when a user selects an article. Only fields applicable to the article are returned (e.g. if the article has no doors, hingePlate options are not included).
268
+
269
+ The values returned are the exact strings the order system expects — do not use variations or paraphrased values.
270
+
271
+ CRITICAL RULE: Present these options to the user and ask them to choose. Do NOT pick a value on the user's behalf. If the user's source document (drawing, spec sheet, etc.) does not explicitly call out a value for a field, it is missing — ask the user before proceeding.`,
272
+ inputSchema: GetArticleOptionsSchema,
273
+ handler: getArticleOptions,
274
+ },
275
+ {
276
+ name: 'get_article_context',
277
+ description: `Load all configuration context for a cabinet article in a single call. Call this immediately when a user selects or expresses interest in an article — before asking them any configuration questions.
278
+
279
+ It returns:
280
+ - Dimension ranges (valid height/width/depth for this article)
281
+ - All applicable configuration options with full guidance (only fields that apply to this specific article based on its feature flags)
282
+
283
+ After calling this, immediately call get_article_options to load the valid selectable values for all applicable fields. Then present the user with a brief summary of all applicable options and their choices.
284
+
285
+ CRITICAL RULE: After presenting the options, you MUST ask the user to specify each value explicitly. Do NOT auto-select, guess, or default any configuration field — not material, not edgebanding, not joint method, not drawer type, nothing. If the user provides a drawing or document that does not call out a value, that value is missing and must be asked for. Only proceed to create_order once the user has confirmed every applicable field.
286
+
287
+ Do NOT call get_configuration_info in a loop — this tool already loads the guidance text at once.`,
288
+ inputSchema: GetArticleContextSchema,
289
+ handler: getArticleContext,
290
+ },
291
+ {
292
+ name: 'get_configuration_info',
293
+ description: `Get full detail for a single configuration field. Use this only when the user explicitly asks for more information about a specific option — not as part of the initial article selection flow (use get_article_context for that instead).
294
+
295
+ Available fields: ${VALID_FIELDS.join(', ')}`,
296
+ inputSchema: GetConfigInfoSchema,
297
+ handler: getConfigurationInfo,
298
+ },
299
+ ];
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configurationTools = void 0;
4
+ exports.getArticleConfiguration = getArticleConfiguration;
5
+ const zod_1 = require("zod");
6
+ const api_client_1 = require("../client/api-client");
7
+ const GetConfigSchema = zod_1.z.object({
8
+ serialNumber: zod_1.z.string().describe('Article serial number'),
9
+ });
10
+ async function getArticleConfiguration(input) {
11
+ try {
12
+ const { data } = await api_client_1.client.get(`/catalog/${input.serialNumber}/configuration`);
13
+ return JSON.stringify(data, null, 2);
14
+ }
15
+ catch (error) {
16
+ try {
17
+ (0, api_client_1.handleAxiosError)(error);
18
+ }
19
+ catch (e) {
20
+ return e.message;
21
+ }
22
+ return 'Unexpected error fetching configuration.';
23
+ }
24
+ }
25
+ exports.configurationTools = [
26
+ {
27
+ name: 'get_article_configuration',
28
+ description: 'Get the raw feature flags and dimension ranges for a cabinet article. For guided user-facing configuration, use get_article_context instead — it loads all applicable options and guidance in one call. Use this tool only when you need the raw boolean flags without the guidance text.',
29
+ inputSchema: GetConfigSchema,
30
+ handler: getArticleConfiguration,
31
+ },
32
+ ];