@assetlab/mcp-server 1.25.1 → 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 +225 -2
- 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)}`;
|
|
@@ -584,13 +595,49 @@ export function registerWriteTools(server, client) {
|
|
|
584
595
|
country: z.string().max(200).optional().describe('Country'),
|
|
585
596
|
description: z.string().optional().describe('Description'),
|
|
586
597
|
square_footage: z.number().min(0).optional().describe('Square footage'),
|
|
587
|
-
cost_per_sqft: z.number().min(0).optional().describe('
|
|
598
|
+
cost_per_sqft: z.number().min(0).optional().describe('Base cost per square foot'),
|
|
599
|
+
additional_cost_per_sqft: z
|
|
600
|
+
.number()
|
|
601
|
+
.min(0)
|
|
602
|
+
.optional()
|
|
603
|
+
.describe('Additional cost per square foot'),
|
|
604
|
+
operational_cost_per_sqft: z
|
|
605
|
+
.number()
|
|
606
|
+
.min(0)
|
|
607
|
+
.optional()
|
|
608
|
+
.describe('Operational cost per square foot'),
|
|
588
609
|
year_built: z.number().int().min(1800).max(2100).optional().describe('Year built'),
|
|
589
610
|
contact_name: z.string().max(500).optional().describe('Primary contact name'),
|
|
590
611
|
contact_email: z.string().max(500).optional().describe('Contact email'),
|
|
591
612
|
contact_phone: z.string().max(50).optional().describe('Contact phone'),
|
|
592
613
|
owner_landlord: z.string().max(500).optional().describe('Property owner or landlord'),
|
|
593
614
|
ownership_type: z.enum(['Owned', 'Leased', 'Managed']).optional().describe('Ownership type'),
|
|
615
|
+
lease_start_date: z.string().max(20).optional().describe('Lease start date (YYYY-MM-DD)'),
|
|
616
|
+
lease_end_date: z.string().max(20).optional().describe('Lease end date (YYYY-MM-DD)'),
|
|
617
|
+
renewal_option: z.string().max(500).optional().describe('Lease renewal option details'),
|
|
618
|
+
lease_details: z.string().optional().describe('Free-text lease details / notes'),
|
|
619
|
+
insurance_provider: z.string().max(500).optional().describe('Insurance provider name'),
|
|
620
|
+
insurance_policy_number: z.string().max(200).optional().describe('Insurance policy number'),
|
|
621
|
+
property_manager_company: z
|
|
622
|
+
.string()
|
|
623
|
+
.max(500)
|
|
624
|
+
.optional()
|
|
625
|
+
.describe('Property management company name'),
|
|
626
|
+
property_manager_contact_name: z
|
|
627
|
+
.string()
|
|
628
|
+
.max(500)
|
|
629
|
+
.optional()
|
|
630
|
+
.describe('Property management contact name'),
|
|
631
|
+
property_manager_contact_email: z
|
|
632
|
+
.string()
|
|
633
|
+
.max(500)
|
|
634
|
+
.optional()
|
|
635
|
+
.describe('Property management contact email'),
|
|
636
|
+
property_manager_contact_phone: z
|
|
637
|
+
.string()
|
|
638
|
+
.max(50)
|
|
639
|
+
.optional()
|
|
640
|
+
.describe('Property management contact phone'),
|
|
594
641
|
}, async (params) => {
|
|
595
642
|
try {
|
|
596
643
|
const result = await client.create('sites', buildBody(params));
|
|
@@ -610,13 +657,49 @@ export function registerWriteTools(server, client) {
|
|
|
610
657
|
country: z.string().max(200).optional().describe('Country'),
|
|
611
658
|
description: z.string().optional().describe('Description'),
|
|
612
659
|
square_footage: z.number().min(0).optional().describe('Square footage'),
|
|
613
|
-
cost_per_sqft: z.number().min(0).optional().describe('
|
|
660
|
+
cost_per_sqft: z.number().min(0).optional().describe('Base cost per square foot'),
|
|
661
|
+
additional_cost_per_sqft: z
|
|
662
|
+
.number()
|
|
663
|
+
.min(0)
|
|
664
|
+
.optional()
|
|
665
|
+
.describe('Additional cost per square foot'),
|
|
666
|
+
operational_cost_per_sqft: z
|
|
667
|
+
.number()
|
|
668
|
+
.min(0)
|
|
669
|
+
.optional()
|
|
670
|
+
.describe('Operational cost per square foot'),
|
|
614
671
|
year_built: z.number().int().min(1800).max(2100).optional().describe('Year built'),
|
|
615
672
|
contact_name: z.string().max(500).optional().describe('Primary contact name'),
|
|
616
673
|
contact_email: z.string().max(500).optional().describe('Contact email'),
|
|
617
674
|
contact_phone: z.string().max(50).optional().describe('Contact phone'),
|
|
618
675
|
owner_landlord: z.string().max(500).optional().describe('Property owner or landlord'),
|
|
619
676
|
ownership_type: z.enum(['Owned', 'Leased', 'Managed']).optional().describe('Ownership type'),
|
|
677
|
+
lease_start_date: z.string().max(20).optional().describe('Lease start date (YYYY-MM-DD)'),
|
|
678
|
+
lease_end_date: z.string().max(20).optional().describe('Lease end date (YYYY-MM-DD)'),
|
|
679
|
+
renewal_option: z.string().max(500).optional().describe('Lease renewal option details'),
|
|
680
|
+
lease_details: z.string().optional().describe('Free-text lease details / notes'),
|
|
681
|
+
insurance_provider: z.string().max(500).optional().describe('Insurance provider name'),
|
|
682
|
+
insurance_policy_number: z.string().max(200).optional().describe('Insurance policy number'),
|
|
683
|
+
property_manager_company: z
|
|
684
|
+
.string()
|
|
685
|
+
.max(500)
|
|
686
|
+
.optional()
|
|
687
|
+
.describe('Property management company name'),
|
|
688
|
+
property_manager_contact_name: z
|
|
689
|
+
.string()
|
|
690
|
+
.max(500)
|
|
691
|
+
.optional()
|
|
692
|
+
.describe('Property management contact name'),
|
|
693
|
+
property_manager_contact_email: z
|
|
694
|
+
.string()
|
|
695
|
+
.max(500)
|
|
696
|
+
.optional()
|
|
697
|
+
.describe('Property management contact email'),
|
|
698
|
+
property_manager_contact_phone: z
|
|
699
|
+
.string()
|
|
700
|
+
.max(50)
|
|
701
|
+
.optional()
|
|
702
|
+
.describe('Property management contact phone'),
|
|
620
703
|
}, async ({ id, ...rest }) => {
|
|
621
704
|
try {
|
|
622
705
|
const result = await client.update('sites', id, buildBody(rest));
|
|
@@ -1065,6 +1148,144 @@ export function registerWriteTools(server, client) {
|
|
|
1065
1148
|
}
|
|
1066
1149
|
});
|
|
1067
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
|
+
// ============================================================
|
|
1068
1289
|
// 9. Projects (scope: projects)
|
|
1069
1290
|
// ============================================================
|
|
1070
1291
|
server.tool('create_project', 'Create a new project. Requires projects:write scope.', {
|
|
@@ -4057,6 +4278,8 @@ export function registerWriteTools(server, client) {
|
|
|
4057
4278
|
'system-classes',
|
|
4058
4279
|
'pm-schedules',
|
|
4059
4280
|
'pm-templates',
|
|
4281
|
+
'form-templates',
|
|
4282
|
+
'form-template-items',
|
|
4060
4283
|
'projects',
|
|
4061
4284
|
'contracts',
|
|
4062
4285
|
'invoices',
|