@assetlab/mcp-server 1.26.0 → 1.27.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/dist/tools-write.js +151 -0
- package/dist/tools-write.js.map +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +124 -0
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/tools-write.js
CHANGED
|
@@ -20,6 +20,17 @@ function buildBody(params) {
|
|
|
20
20
|
return body;
|
|
21
21
|
}
|
|
22
22
|
const PM_RESOURCE_TYPES = ['TOOL', 'PART', 'MATERIAL', 'EQUIPMENT'];
|
|
23
|
+
const FORM_TEMPLATE_CATEGORIES = ['task_checklist', 'inspection', 'compliance', 'survey'];
|
|
24
|
+
const FORM_TEMPLATE_STATUSES = ['draft', 'published', 'archived'];
|
|
25
|
+
const FORM_ITEM_TYPES = [
|
|
26
|
+
'section',
|
|
27
|
+
'checkbox',
|
|
28
|
+
'single_select',
|
|
29
|
+
'multi_select',
|
|
30
|
+
'number',
|
|
31
|
+
'text',
|
|
32
|
+
'photo',
|
|
33
|
+
];
|
|
23
34
|
function randomTaskId() {
|
|
24
35
|
const g = globalThis;
|
|
25
36
|
return g.crypto?.randomUUID?.() ?? `task_${Math.random().toString(36).slice(2, 12)}`;
|
|
@@ -1137,6 +1148,144 @@ export function registerWriteTools(server, client) {
|
|
|
1137
1148
|
}
|
|
1138
1149
|
});
|
|
1139
1150
|
// ============================================================
|
|
1151
|
+
// 8c. Forms & Inspections (scope: form_templates, form_template_items)
|
|
1152
|
+
// ============================================================
|
|
1153
|
+
server.tool('create_form_template', 'Create a form template — a reusable inspection, checklist, compliance, or survey definition. Step 1 of building a form: create it as a draft, then add questions with create_form_template_item (or bulk_create on form-template-items), then publish with update_form_template status=published (publishing is rejected if any question is malformed). Requires form_templates:write scope.', {
|
|
1154
|
+
name: z.string().min(1).max(500).describe('Form template name (required)'),
|
|
1155
|
+
description: z.string().max(5000).optional().describe('Description'),
|
|
1156
|
+
category: z
|
|
1157
|
+
.enum(FORM_TEMPLATE_CATEGORIES)
|
|
1158
|
+
.optional()
|
|
1159
|
+
.describe('Form category: inspection (default), task_checklist, compliance, or survey. Manufacturer-recommended equipment checks → inspection.'),
|
|
1160
|
+
status: z
|
|
1161
|
+
.enum(FORM_TEMPLATE_STATUSES)
|
|
1162
|
+
.optional()
|
|
1163
|
+
.describe('Publication status — leave as draft (default) until all questions are added.'),
|
|
1164
|
+
}, async (params) => {
|
|
1165
|
+
try {
|
|
1166
|
+
const result = await client.create('form-templates', buildBody(params));
|
|
1167
|
+
return formatResult(result);
|
|
1168
|
+
}
|
|
1169
|
+
catch (err) {
|
|
1170
|
+
return formatError(err);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
server.tool('update_form_template', 'Update an existing form template by ID. Requires form_templates:write scope.', {
|
|
1174
|
+
id: z.string().uuid().describe('Form template ID'),
|
|
1175
|
+
name: z.string().min(1).max(500).optional().describe('Form template name'),
|
|
1176
|
+
description: z.string().max(5000).optional().describe('Description'),
|
|
1177
|
+
category: z
|
|
1178
|
+
.enum(FORM_TEMPLATE_CATEGORIES)
|
|
1179
|
+
.optional()
|
|
1180
|
+
.describe('Form category (task_checklist, inspection, compliance, or survey)'),
|
|
1181
|
+
status: z
|
|
1182
|
+
.enum(FORM_TEMPLATE_STATUSES)
|
|
1183
|
+
.optional()
|
|
1184
|
+
.describe('Publication status (draft, published, or archived)'),
|
|
1185
|
+
}, async ({ id, ...rest }) => {
|
|
1186
|
+
try {
|
|
1187
|
+
const result = await client.update('form-templates', id, buildBody(rest));
|
|
1188
|
+
return formatResult(result);
|
|
1189
|
+
}
|
|
1190
|
+
catch (err) {
|
|
1191
|
+
return formatError(err);
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
server.tool('delete_form_template', 'Delete a form template by ID. Requires form_templates:write scope.', { id: z.string().uuid().describe('Form template ID') }, async ({ id }) => {
|
|
1195
|
+
try {
|
|
1196
|
+
const result = await client.remove('form-templates', id);
|
|
1197
|
+
return formatResult(result);
|
|
1198
|
+
}
|
|
1199
|
+
catch (err) {
|
|
1200
|
+
return formatError(err);
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
server.tool('create_form_template_item', 'Add one question (item) to a form template. Build a form by calling this once per question in order, or use bulk_create on form-template-items. Requires form_template_items:write scope.', {
|
|
1204
|
+
template_id: z.string().uuid().describe('Form template ID — resolve via list_form_templates'),
|
|
1205
|
+
item_key: z
|
|
1206
|
+
.string()
|
|
1207
|
+
.min(1)
|
|
1208
|
+
.max(200)
|
|
1209
|
+
.optional()
|
|
1210
|
+
.describe('Optional stable key, unique within the template. OMIT IT and the server derives one from the label (recommended). Only set it when a later item’s visible_when must reference this one — then use a short slug like "compressor_status".'),
|
|
1211
|
+
sort_order: z
|
|
1212
|
+
.number()
|
|
1213
|
+
.int()
|
|
1214
|
+
.min(0)
|
|
1215
|
+
.describe('Display order within the template (0-based; questions render in this order)'),
|
|
1216
|
+
item_type: z
|
|
1217
|
+
.enum(FORM_ITEM_TYPES)
|
|
1218
|
+
.describe('Pick by the answer you want: single_select = exactly one choice (Pass/Fail, Yes/No, Yes/No/N-A, or custom — supply options); multi_select = pick several (supply options); number = a numeric reading/count (use config.min/max/unit/integer); checkbox = a single done/not-done tick; text = free comment (config.multiline for long text); photo = photo evidence (config.maxPhotos); section = a non-answerable heading that groups the questions under it.'),
|
|
1219
|
+
label: z.string().min(1).max(2000).describe('Question text / prompt shown to the user'),
|
|
1220
|
+
help_text: z.string().max(5000).optional().describe('Optional hint shown under the label'),
|
|
1221
|
+
required: z
|
|
1222
|
+
.boolean()
|
|
1223
|
+
.optional()
|
|
1224
|
+
.describe('Whether an answer is required to complete the form (default false)'),
|
|
1225
|
+
options: z
|
|
1226
|
+
.array(z.object({ value: z.string(), label: z.string() }))
|
|
1227
|
+
.optional()
|
|
1228
|
+
.describe('REQUIRED for single_select/multi_select: at least 2 choices as { value, label } with unique values. value is a machine slug (e.g. "fail"), label is shown to the user (e.g. "Fail"). Omit for other types.'),
|
|
1229
|
+
config: z
|
|
1230
|
+
.record(z.unknown())
|
|
1231
|
+
.optional()
|
|
1232
|
+
.describe('Per-type settings. number: { min, max, unit, integer, decimals }. text: { multiline, maxLength, placeholder }. multi_select: { minSelections, maxSelections }. photo: { minPhotos, maxPhotos }.'),
|
|
1233
|
+
visible_when: z
|
|
1234
|
+
.object({ itemKey: z.string(), op: z.string(), value: z.unknown().optional() })
|
|
1235
|
+
.nullable()
|
|
1236
|
+
.optional()
|
|
1237
|
+
.describe('Optional conditional visibility { itemKey, op, value }. itemKey must reference an EARLIER item’s key (set that item’s item_key explicitly). Operators by referenced type — single_select/checkbox: equals, not_equals, in, not_in, is_answered, is_blank; number: gt, lt, gte, lte, equals, not_equals, is_answered, is_blank; text: is_answered, is_blank, equals, not_equals; multi_select: in, not_in, is_answered, is_blank. e.g. show a "Details" text item only when item "compressor_status" equals "fail".'),
|
|
1238
|
+
}, async (params) => {
|
|
1239
|
+
try {
|
|
1240
|
+
const result = await client.create('form-template-items', buildBody(params));
|
|
1241
|
+
return formatResult(result);
|
|
1242
|
+
}
|
|
1243
|
+
catch (err) {
|
|
1244
|
+
return formatError(err);
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
server.tool('update_form_template_item', 'Update an existing form template item by ID. template_id and item_key are immutable and cannot be changed. Requires form_template_items:write scope.', {
|
|
1248
|
+
id: z.string().uuid().describe('Form template item ID'),
|
|
1249
|
+
sort_order: z.number().int().min(0).optional().describe('Display order within the template'),
|
|
1250
|
+
item_type: z
|
|
1251
|
+
.enum(FORM_ITEM_TYPES)
|
|
1252
|
+
.optional()
|
|
1253
|
+
.describe('Item type (section, checkbox, single_select, multi_select, number, text, photo)'),
|
|
1254
|
+
label: z.string().min(1).max(2000).optional().describe('Question label / prompt'),
|
|
1255
|
+
help_text: z.string().max(5000).optional().describe('Help text shown under the label'),
|
|
1256
|
+
required: z.boolean().optional().describe('Whether an answer is required'),
|
|
1257
|
+
options: z
|
|
1258
|
+
.array(z.object({ value: z.string(), label: z.string() }))
|
|
1259
|
+
.optional()
|
|
1260
|
+
.describe('Choices for single_select / multi_select items'),
|
|
1261
|
+
config: z
|
|
1262
|
+
.record(z.unknown())
|
|
1263
|
+
.optional()
|
|
1264
|
+
.describe('Per-type configuration (e.g. { min, max, unit, multiline })'),
|
|
1265
|
+
visible_when: z
|
|
1266
|
+
.object({ itemKey: z.string(), op: z.string(), value: z.unknown().optional() })
|
|
1267
|
+
.nullable()
|
|
1268
|
+
.optional()
|
|
1269
|
+
.describe('Conditional-visibility rule referencing another item'),
|
|
1270
|
+
}, async ({ id, ...rest }) => {
|
|
1271
|
+
try {
|
|
1272
|
+
const result = await client.update('form-template-items', id, buildBody(rest));
|
|
1273
|
+
return formatResult(result);
|
|
1274
|
+
}
|
|
1275
|
+
catch (err) {
|
|
1276
|
+
return formatError(err);
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
server.tool('delete_form_template_item', 'Delete a form template item by ID. Requires form_template_items:write scope.', { id: z.string().uuid().describe('Form template item ID') }, async ({ id }) => {
|
|
1280
|
+
try {
|
|
1281
|
+
const result = await client.remove('form-template-items', id);
|
|
1282
|
+
return formatResult(result);
|
|
1283
|
+
}
|
|
1284
|
+
catch (err) {
|
|
1285
|
+
return formatError(err);
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
// ============================================================
|
|
1140
1289
|
// 9. Projects (scope: projects)
|
|
1141
1290
|
// ============================================================
|
|
1142
1291
|
server.tool('create_project', 'Create a new project. Requires projects:write scope.', {
|
|
@@ -4129,6 +4278,8 @@ export function registerWriteTools(server, client) {
|
|
|
4129
4278
|
'system-classes',
|
|
4130
4279
|
'pm-schedules',
|
|
4131
4280
|
'pm-templates',
|
|
4281
|
+
'form-templates',
|
|
4282
|
+
'form-template-items',
|
|
4132
4283
|
'projects',
|
|
4133
4284
|
'contracts',
|
|
4134
4285
|
'invoices',
|