@assetlab/mcp-server 1.0.3 → 1.2.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/README.md +174 -112
- package/dist/client.d.ts +11 -0
- package/dist/client.js +53 -0
- package/dist/client.js.map +1 -1
- package/dist/oauth.d.ts +20 -0
- package/dist/oauth.js +331 -0
- package/dist/oauth.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +818 -18
- package/dist/tools.js.map +1 -1
- package/dist/worker.d.ts +19 -0
- package/dist/worker.js +121 -0
- package/dist/worker.js.map +1 -0
- package/package.json +13 -5
package/dist/tools.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP tool registrations for AssetLab.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Tools map to endpoints on the AssetLab API Gateway.
|
|
5
|
+
* Write tools require API keys with the appropriate scope (e.g. parts:write).
|
|
6
6
|
*/
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
// Shared schema fragments
|
|
8
|
+
// Shared schema fragments — pagination is handled automatically via listAll()
|
|
9
|
+
// but still exposed for direct API users who want manual control
|
|
9
10
|
const paginationSchema = {
|
|
10
|
-
page: z.number().int().min(1).optional().describe('Page number (default:
|
|
11
|
-
per_page: z.number().int().min(1).max(
|
|
11
|
+
page: z.number().int().min(1).optional().describe('Page number (default: all pages fetched automatically)'),
|
|
12
|
+
per_page: z.number().int().min(1).max(1000).optional().describe('Items per page (default: 1000, max: 1000). All pages are fetched automatically.'),
|
|
12
13
|
};
|
|
13
14
|
const searchSchema = {
|
|
14
15
|
search: z.string().max(200).optional().describe('Search by name'),
|
|
@@ -21,6 +22,17 @@ function formatError(err) {
|
|
|
21
22
|
const message = err instanceof Error ? err.message : String(err);
|
|
22
23
|
return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Smart list: if user explicitly passes page/per_page, use single-page list().
|
|
27
|
+
* Otherwise, auto-paginate with listAll() to return complete data.
|
|
28
|
+
*/
|
|
29
|
+
async function smartList(client, resource, params) {
|
|
30
|
+
const { page, per_page, ...filters } = params;
|
|
31
|
+
if (page !== undefined || per_page !== undefined) {
|
|
32
|
+
return client.list(resource, params);
|
|
33
|
+
}
|
|
34
|
+
return client.listAll(resource, filters);
|
|
35
|
+
}
|
|
24
36
|
export function registerTools(server, client) {
|
|
25
37
|
// ============================================================
|
|
26
38
|
// Assets
|
|
@@ -33,7 +45,7 @@ export function registerTools(server, client) {
|
|
|
33
45
|
system_id: z.string().uuid().optional().describe('Filter by system ID'),
|
|
34
46
|
}, async (params) => {
|
|
35
47
|
try {
|
|
36
|
-
const result = await client
|
|
48
|
+
const result = await smartList(client, 'assets', params);
|
|
37
49
|
return formatResult(result);
|
|
38
50
|
}
|
|
39
51
|
catch (err) {
|
|
@@ -61,7 +73,7 @@ export function registerTools(server, client) {
|
|
|
61
73
|
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
62
74
|
}, async (params) => {
|
|
63
75
|
try {
|
|
64
|
-
const result = await client
|
|
76
|
+
const result = await smartList(client, 'work-orders', params);
|
|
65
77
|
return formatResult(result);
|
|
66
78
|
}
|
|
67
79
|
catch (err) {
|
|
@@ -86,7 +98,7 @@ export function registerTools(server, client) {
|
|
|
86
98
|
city: z.string().max(100).optional().describe('Filter by city name'),
|
|
87
99
|
}, async (params) => {
|
|
88
100
|
try {
|
|
89
|
-
const result = await client
|
|
101
|
+
const result = await smartList(client, 'sites', params);
|
|
90
102
|
return formatResult(result);
|
|
91
103
|
}
|
|
92
104
|
catch (err) {
|
|
@@ -111,7 +123,7 @@ export function registerTools(server, client) {
|
|
|
111
123
|
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
112
124
|
}, async (params) => {
|
|
113
125
|
try {
|
|
114
|
-
const result = await client
|
|
126
|
+
const result = await smartList(client, 'buildings', params);
|
|
115
127
|
return formatResult(result);
|
|
116
128
|
}
|
|
117
129
|
catch (err) {
|
|
@@ -127,7 +139,7 @@ export function registerTools(server, client) {
|
|
|
127
139
|
building_id: z.string().uuid().optional().describe('Filter by building ID'),
|
|
128
140
|
}, async (params) => {
|
|
129
141
|
try {
|
|
130
|
-
const result = await client
|
|
142
|
+
const result = await smartList(client, 'locations', params);
|
|
131
143
|
return formatResult(result);
|
|
132
144
|
}
|
|
133
145
|
catch (err) {
|
|
@@ -143,7 +155,7 @@ export function registerTools(server, client) {
|
|
|
143
155
|
system_group_id: z.string().uuid().optional().describe('Filter by system group ID'),
|
|
144
156
|
}, async (params) => {
|
|
145
157
|
try {
|
|
146
|
-
const result = await client
|
|
158
|
+
const result = await smartList(client, 'systems', params);
|
|
147
159
|
return formatResult(result);
|
|
148
160
|
}
|
|
149
161
|
catch (err) {
|
|
@@ -156,7 +168,7 @@ export function registerTools(server, client) {
|
|
|
156
168
|
system_class_id: z.string().uuid().optional().describe('Filter by system class ID'),
|
|
157
169
|
}, async (params) => {
|
|
158
170
|
try {
|
|
159
|
-
const result = await client
|
|
171
|
+
const result = await smartList(client, 'system-groups', params);
|
|
160
172
|
return formatResult(result);
|
|
161
173
|
}
|
|
162
174
|
catch (err) {
|
|
@@ -168,7 +180,7 @@ export function registerTools(server, client) {
|
|
|
168
180
|
...paginationSchema,
|
|
169
181
|
}, async (params) => {
|
|
170
182
|
try {
|
|
171
|
-
const result = await client
|
|
183
|
+
const result = await smartList(client, 'system-classes', params);
|
|
172
184
|
return formatResult(result);
|
|
173
185
|
}
|
|
174
186
|
catch (err) {
|
|
@@ -186,7 +198,7 @@ export function registerTools(server, client) {
|
|
|
186
198
|
frequency: z.string().optional().describe('Filter by frequency: DAILY, WEEKLY, MONTHLY, QUARTERLY, SEMI_ANNUAL, ANNUAL, FIVE_YEARLY, CUSTOM'),
|
|
187
199
|
}, async (params) => {
|
|
188
200
|
try {
|
|
189
|
-
const result = await client
|
|
201
|
+
const result = await smartList(client, 'pm-schedules', params);
|
|
190
202
|
return formatResult(result);
|
|
191
203
|
}
|
|
192
204
|
catch (err) {
|
|
@@ -210,7 +222,7 @@ export function registerTools(server, client) {
|
|
|
210
222
|
...paginationSchema,
|
|
211
223
|
}, async (params) => {
|
|
212
224
|
try {
|
|
213
|
-
const result = await client
|
|
225
|
+
const result = await smartList(client, 'pm-templates', params);
|
|
214
226
|
return formatResult(result);
|
|
215
227
|
}
|
|
216
228
|
catch (err) {
|
|
@@ -227,7 +239,7 @@ export function registerTools(server, client) {
|
|
|
227
239
|
health_status: z.string().optional().describe('Filter by health: on_track, at_risk, delayed, critical'),
|
|
228
240
|
}, async (params) => {
|
|
229
241
|
try {
|
|
230
|
-
const result = await client
|
|
242
|
+
const result = await smartList(client, 'projects', params);
|
|
231
243
|
return formatResult(result);
|
|
232
244
|
}
|
|
233
245
|
catch (err) {
|
|
@@ -252,7 +264,7 @@ export function registerTools(server, client) {
|
|
|
252
264
|
category: z.string().max(100).optional().describe('Filter by contract category'),
|
|
253
265
|
}, async (params) => {
|
|
254
266
|
try {
|
|
255
|
-
const result = await client
|
|
267
|
+
const result = await smartList(client, 'contracts', params);
|
|
256
268
|
return formatResult(result);
|
|
257
269
|
}
|
|
258
270
|
catch (err) {
|
|
@@ -269,7 +281,7 @@ export function registerTools(server, client) {
|
|
|
269
281
|
system_id: z.string().uuid().optional().describe('Filter by system ID'),
|
|
270
282
|
}, async (params) => {
|
|
271
283
|
try {
|
|
272
|
-
const result = await client
|
|
284
|
+
const result = await smartList(client, 'compliance', params);
|
|
273
285
|
return formatResult(result);
|
|
274
286
|
}
|
|
275
287
|
catch (err) {
|
|
@@ -286,6 +298,324 @@ export function registerTools(server, client) {
|
|
|
286
298
|
}
|
|
287
299
|
});
|
|
288
300
|
// ============================================================
|
|
301
|
+
// Parts
|
|
302
|
+
// ============================================================
|
|
303
|
+
server.tool('list_parts', 'List parts/inventory items. Filter by site or category.', {
|
|
304
|
+
...searchSchema,
|
|
305
|
+
...paginationSchema,
|
|
306
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
307
|
+
category: z.string().max(100).optional().describe('Filter by category (partial match)'),
|
|
308
|
+
}, async (params) => {
|
|
309
|
+
try {
|
|
310
|
+
const result = await smartList(client, 'parts', params);
|
|
311
|
+
return formatResult(result);
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
return formatError(err);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
server.tool('get_part', 'Get detailed information about a specific part including location and stock levels.', { id: uuidParam.describe('Part ID') }, async ({ id }) => {
|
|
318
|
+
try {
|
|
319
|
+
const result = await client.getOne('parts', id);
|
|
320
|
+
return formatResult(result);
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
return formatError(err);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
server.tool('create_part', 'Create a new part/inventory item. Requires parts:write scope.', {
|
|
327
|
+
name: z.string().min(1).max(500).describe('Part name (required)'),
|
|
328
|
+
part_number: z.string().max(200).optional().describe('Part number / SKU'),
|
|
329
|
+
category: z.string().max(200).optional().describe('Category label'),
|
|
330
|
+
supplier: z.string().max(500).optional().describe('Supplier name'),
|
|
331
|
+
cost: z.number().min(0).optional().describe('Unit cost'),
|
|
332
|
+
quantity: z.number().int().min(0).max(10_000_000).optional().describe('Current stock quantity'),
|
|
333
|
+
desired_quantity: z.number().int().min(0).max(10_000_000).optional().describe('Target / reorder quantity'),
|
|
334
|
+
specific_location: z.string().max(500).optional().describe('Storage location description'),
|
|
335
|
+
site_id: z.string().uuid().optional().describe('Site ID'),
|
|
336
|
+
building_id: z.string().uuid().optional().describe('Building ID'),
|
|
337
|
+
location_id: z.string().uuid().optional().describe('Location ID'),
|
|
338
|
+
}, async (params) => {
|
|
339
|
+
try {
|
|
340
|
+
const body = {};
|
|
341
|
+
for (const [k, v] of Object.entries(params)) {
|
|
342
|
+
if (v !== undefined)
|
|
343
|
+
body[k] = v;
|
|
344
|
+
}
|
|
345
|
+
const result = await client.create('parts', body);
|
|
346
|
+
return formatResult(result);
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
return formatError(err);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
// ============================================================
|
|
353
|
+
// Vendors
|
|
354
|
+
// ============================================================
|
|
355
|
+
server.tool('list_vendors', 'List vendors. Filter by status, category, or city.', {
|
|
356
|
+
...searchSchema,
|
|
357
|
+
...paginationSchema,
|
|
358
|
+
status: z.string().optional().describe('Filter by vendor status'),
|
|
359
|
+
category: z.string().max(100).optional().describe('Filter by category (partial match)'),
|
|
360
|
+
city: z.string().max(100).optional().describe('Filter by city (partial match)'),
|
|
361
|
+
}, async (params) => {
|
|
362
|
+
try {
|
|
363
|
+
const result = await smartList(client, 'vendors', params);
|
|
364
|
+
return formatResult(result);
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
return formatError(err);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
server.tool('get_vendor', 'Get detailed vendor information including contact details, address, and website.', { id: uuidParam.describe('Vendor ID') }, async ({ id }) => {
|
|
371
|
+
try {
|
|
372
|
+
const result = await client.getOne('vendors', id);
|
|
373
|
+
return formatResult(result);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
return formatError(err);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
// ============================================================
|
|
380
|
+
// Work Requests
|
|
381
|
+
// ============================================================
|
|
382
|
+
server.tool('list_work_requests', 'List work requests (submitted by requesters). Filter by status (SUBMITTED, APPROVED, REJECTED, CONVERTED) or priority.', {
|
|
383
|
+
...searchSchema,
|
|
384
|
+
...paginationSchema,
|
|
385
|
+
status: z.string().optional().describe('Filter by status: SUBMITTED, APPROVED, REJECTED, CONVERTED'),
|
|
386
|
+
priority: z.string().optional().describe('Filter by priority: LOW, MEDIUM, HIGH, CRITICAL'),
|
|
387
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
388
|
+
}, async (params) => {
|
|
389
|
+
try {
|
|
390
|
+
const result = await smartList(client, 'work-requests', params);
|
|
391
|
+
return formatResult(result);
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
return formatError(err);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
server.tool('get_work_request', 'Get detailed work request information including description, attachments, and processing status.', { id: uuidParam.describe('Work request ID') }, async ({ id }) => {
|
|
398
|
+
try {
|
|
399
|
+
const result = await client.getOne('work-requests', id);
|
|
400
|
+
return formatResult(result);
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
return formatError(err);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
// ============================================================
|
|
407
|
+
// Invoices
|
|
408
|
+
// ============================================================
|
|
409
|
+
server.tool('list_invoices', 'List invoices. Filter by status (pending, approved, paid, voided), vendor, or project.', {
|
|
410
|
+
...searchSchema,
|
|
411
|
+
...paginationSchema,
|
|
412
|
+
status: z.string().optional().describe('Filter by status: pending, approved, paid, voided'),
|
|
413
|
+
vendor_id: z.string().uuid().optional().describe('Filter by vendor ID'),
|
|
414
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
415
|
+
}, async (params) => {
|
|
416
|
+
try {
|
|
417
|
+
const result = await smartList(client, 'invoices', params);
|
|
418
|
+
return formatResult(result);
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
return formatError(err);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
server.tool('get_invoice', 'Get detailed invoice information including amounts, dates, linked vendor, project, and purchase order.', { id: uuidParam.describe('Invoice ID') }, async ({ id }) => {
|
|
425
|
+
try {
|
|
426
|
+
const result = await client.getOne('invoices', id);
|
|
427
|
+
return formatResult(result);
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
return formatError(err);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
// ============================================================
|
|
434
|
+
// Purchase Orders
|
|
435
|
+
// ============================================================
|
|
436
|
+
server.tool('list_purchase_orders', 'List purchase orders. Filter by status (draft, issued, partially_received, received, closed, cancelled), vendor, or project.', {
|
|
437
|
+
...searchSchema,
|
|
438
|
+
...paginationSchema,
|
|
439
|
+
status: z.string().optional().describe('Filter by status: draft, issued, partially_received, received, closed, cancelled'),
|
|
440
|
+
vendor_id: z.string().uuid().optional().describe('Filter by vendor ID'),
|
|
441
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
442
|
+
}, async (params) => {
|
|
443
|
+
try {
|
|
444
|
+
const result = await smartList(client, 'purchase-orders', params);
|
|
445
|
+
return formatResult(result);
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
return formatError(err);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
server.tool('get_purchase_order', 'Get detailed purchase order information including amount, status, vendor, and linked project.', { id: uuidParam.describe('Purchase order ID') }, async ({ id }) => {
|
|
452
|
+
try {
|
|
453
|
+
const result = await client.getOne('purchase-orders', id);
|
|
454
|
+
return formatResult(result);
|
|
455
|
+
}
|
|
456
|
+
catch (err) {
|
|
457
|
+
return formatError(err);
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
// ============================================================
|
|
461
|
+
// Expenses
|
|
462
|
+
// ============================================================
|
|
463
|
+
server.tool('list_expenses', 'List expenses. Filter by project, work order, or cost category.', {
|
|
464
|
+
...searchSchema,
|
|
465
|
+
...paginationSchema,
|
|
466
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
467
|
+
work_order_id: z.string().uuid().optional().describe('Filter by work order ID'),
|
|
468
|
+
category_id: z.string().uuid().optional().describe('Filter by cost category ID'),
|
|
469
|
+
}, async (params) => {
|
|
470
|
+
try {
|
|
471
|
+
const result = await smartList(client, 'expenses', params);
|
|
472
|
+
return formatResult(result);
|
|
473
|
+
}
|
|
474
|
+
catch (err) {
|
|
475
|
+
return formatError(err);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
server.tool('get_expense', 'Get detailed expense information including amount, date, receipt, and linked project or work order.', { id: uuidParam.describe('Expense ID') }, async ({ id }) => {
|
|
479
|
+
try {
|
|
480
|
+
const result = await client.getOne('expenses', id);
|
|
481
|
+
return formatResult(result);
|
|
482
|
+
}
|
|
483
|
+
catch (err) {
|
|
484
|
+
return formatError(err);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
// ============================================================
|
|
488
|
+
// Asset Types
|
|
489
|
+
// ============================================================
|
|
490
|
+
server.tool('list_asset_types', 'List asset type classifications. Filter by category or group.', {
|
|
491
|
+
...searchSchema,
|
|
492
|
+
...paginationSchema,
|
|
493
|
+
category: z.string().max(100).optional().describe('Filter by category (partial match)'),
|
|
494
|
+
group_id: z.string().uuid().optional().describe('Filter by asset type group ID'),
|
|
495
|
+
}, async (params) => {
|
|
496
|
+
try {
|
|
497
|
+
const result = await smartList(client, 'asset-types', params);
|
|
498
|
+
return formatResult(result);
|
|
499
|
+
}
|
|
500
|
+
catch (err) {
|
|
501
|
+
return formatError(err);
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
// ============================================================
|
|
505
|
+
// Work Categories
|
|
506
|
+
// ============================================================
|
|
507
|
+
server.tool('list_work_categories', 'List work categories used to classify work orders and requests.', {
|
|
508
|
+
...searchSchema,
|
|
509
|
+
...paginationSchema,
|
|
510
|
+
}, async (params) => {
|
|
511
|
+
try {
|
|
512
|
+
const result = await smartList(client, 'work-categories', params);
|
|
513
|
+
return formatResult(result);
|
|
514
|
+
}
|
|
515
|
+
catch (err) {
|
|
516
|
+
return formatError(err);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
// ============================================================
|
|
520
|
+
// Manufacturers
|
|
521
|
+
// ============================================================
|
|
522
|
+
server.tool('list_manufacturers', 'List manufacturers of equipment and assets.', {
|
|
523
|
+
...searchSchema,
|
|
524
|
+
...paginationSchema,
|
|
525
|
+
}, async (params) => {
|
|
526
|
+
try {
|
|
527
|
+
const result = await smartList(client, 'manufacturers', params);
|
|
528
|
+
return formatResult(result);
|
|
529
|
+
}
|
|
530
|
+
catch (err) {
|
|
531
|
+
return formatError(err);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
server.tool('get_manufacturer', 'Get detailed manufacturer information including contact details and associated system classes.', { id: uuidParam.describe('Manufacturer ID') }, async ({ id }) => {
|
|
535
|
+
try {
|
|
536
|
+
const result = await client.getOne('manufacturers', id);
|
|
537
|
+
return formatResult(result);
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
return formatError(err);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
// ============================================================
|
|
544
|
+
// Building Types
|
|
545
|
+
// ============================================================
|
|
546
|
+
server.tool('list_building_types', 'List building type classifications.', {
|
|
547
|
+
...searchSchema,
|
|
548
|
+
...paginationSchema,
|
|
549
|
+
}, async (params) => {
|
|
550
|
+
try {
|
|
551
|
+
const result = await smartList(client, 'building-types', params);
|
|
552
|
+
return formatResult(result);
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
return formatError(err);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
// ============================================================
|
|
559
|
+
// Location Types
|
|
560
|
+
// ============================================================
|
|
561
|
+
server.tool('list_location_types', 'List location type classifications (e.g., room types, floor types).', {
|
|
562
|
+
...searchSchema,
|
|
563
|
+
...paginationSchema,
|
|
564
|
+
}, async (params) => {
|
|
565
|
+
try {
|
|
566
|
+
const result = await smartList(client, 'location-types', params);
|
|
567
|
+
return formatResult(result);
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
return formatError(err);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
// ============================================================
|
|
574
|
+
// Cost Categories
|
|
575
|
+
// ============================================================
|
|
576
|
+
server.tool('list_cost_categories', 'List cost categories used to classify expenses, invoices, and purchase orders. Supports hierarchical parent-child structure.', {
|
|
577
|
+
...searchSchema,
|
|
578
|
+
...paginationSchema,
|
|
579
|
+
is_active: z.enum(['true', 'false']).optional().describe('Filter by active status'),
|
|
580
|
+
parent_id: z.string().uuid().optional().describe('Filter by parent category ID'),
|
|
581
|
+
}, async (params) => {
|
|
582
|
+
try {
|
|
583
|
+
const result = await smartList(client, 'cost-categories', params);
|
|
584
|
+
return formatResult(result);
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
return formatError(err);
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
// ============================================================
|
|
591
|
+
// Budgets (annual_funding_budgets)
|
|
592
|
+
// ============================================================
|
|
593
|
+
server.tool('list_budgets', 'List annual funding budgets. Filter by year, site, building, or funding source. Includes allocated, budgeted, and remaining amounts.', {
|
|
594
|
+
...searchSchema,
|
|
595
|
+
...paginationSchema,
|
|
596
|
+
year: z.number().int().optional().describe('Filter by budget year (e.g. 2026)'),
|
|
597
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
598
|
+
building_id: z.string().uuid().optional().describe('Filter by building ID'),
|
|
599
|
+
funding_source: z.number().int().optional().describe('Filter by funding source'),
|
|
600
|
+
}, async (params) => {
|
|
601
|
+
try {
|
|
602
|
+
const result = await smartList(client, 'budgets', params);
|
|
603
|
+
return formatResult(result);
|
|
604
|
+
}
|
|
605
|
+
catch (err) {
|
|
606
|
+
return formatError(err);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
server.tool('get_budget', 'Get a single annual funding budget by ID. Use list_sites/list_buildings to resolve site_id/building_id.', { id: uuidParam.describe('Budget ID') }, async ({ id }) => {
|
|
610
|
+
try {
|
|
611
|
+
const result = await client.getOne('budgets', id);
|
|
612
|
+
return formatResult(result);
|
|
613
|
+
}
|
|
614
|
+
catch (err) {
|
|
615
|
+
return formatError(err);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
// ============================================================
|
|
289
619
|
// Dashboard
|
|
290
620
|
// ============================================================
|
|
291
621
|
server.tool('get_dashboard_summary', 'Get aggregated dashboard statistics: total assets, work orders by status, overdue count, active PM schedules, sites, and buildings.', {}, async () => {
|
|
@@ -297,5 +627,475 @@ export function registerTools(server, client) {
|
|
|
297
627
|
return formatError(err);
|
|
298
628
|
}
|
|
299
629
|
});
|
|
630
|
+
// ============================================================
|
|
631
|
+
// Asset Comments
|
|
632
|
+
// ============================================================
|
|
633
|
+
server.tool('list_asset_comments', 'List comments on assets. Filter by asset_id to get comments for a specific asset.', {
|
|
634
|
+
...paginationSchema,
|
|
635
|
+
asset_id: z.string().uuid().optional().describe('Filter by asset ID'),
|
|
636
|
+
}, async (params) => {
|
|
637
|
+
try {
|
|
638
|
+
const result = await smartList(client, 'asset-comments', params);
|
|
639
|
+
return formatResult(result);
|
|
640
|
+
}
|
|
641
|
+
catch (err) {
|
|
642
|
+
return formatError(err);
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
server.tool('get_asset_comment', 'Get a single asset comment by ID.', { id: uuidParam.describe('Asset comment ID') }, async ({ id }) => {
|
|
646
|
+
try {
|
|
647
|
+
const result = await client.getOne('asset-comments', id);
|
|
648
|
+
return formatResult(result);
|
|
649
|
+
}
|
|
650
|
+
catch (err) {
|
|
651
|
+
return formatError(err);
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
// ============================================================
|
|
655
|
+
// Asset Costs
|
|
656
|
+
// ============================================================
|
|
657
|
+
server.tool('list_asset_costs', 'List asset cost records (repairs, PM, operations, replacements, decommissions). Filter by asset, site, category, or work order.', {
|
|
658
|
+
...paginationSchema,
|
|
659
|
+
asset_id: z.string().uuid().optional().describe('Filter by asset ID'),
|
|
660
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
661
|
+
category: z.enum(['Repair', 'PM', 'Operation', 'Replacement', 'Decommission']).optional().describe('Filter by cost category'),
|
|
662
|
+
work_order_id: z.string().uuid().optional().describe('Filter by work order ID'),
|
|
663
|
+
}, async (params) => {
|
|
664
|
+
try {
|
|
665
|
+
const result = await smartList(client, 'asset-costs', params);
|
|
666
|
+
return formatResult(result);
|
|
667
|
+
}
|
|
668
|
+
catch (err) {
|
|
669
|
+
return formatError(err);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
server.tool('get_asset_cost', 'Get a single asset cost record by ID, including related asset, site, and building names.', { id: uuidParam.describe('Asset cost ID') }, async ({ id }) => {
|
|
673
|
+
try {
|
|
674
|
+
const result = await client.getOne('asset-costs', id);
|
|
675
|
+
return formatResult(result);
|
|
676
|
+
}
|
|
677
|
+
catch (err) {
|
|
678
|
+
return formatError(err);
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
// ============================================================
|
|
682
|
+
// Asset Replacement Plans
|
|
683
|
+
// ============================================================
|
|
684
|
+
server.tool('list_asset_replacement_plans', 'List asset replacement plans for lifecycle/capital planning. Filter by asset, status, priority, or planned year.', {
|
|
685
|
+
...paginationSchema,
|
|
686
|
+
asset_id: z.string().uuid().optional().describe('Filter by asset ID'),
|
|
687
|
+
status: z.enum(['PLANNED', 'BUDGETED', 'APPROVED', 'COMPLETED', 'CANCELLED']).optional().describe('Filter by plan status'),
|
|
688
|
+
priority: z.enum(['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']).optional().describe('Filter by priority'),
|
|
689
|
+
year: z.number().int().optional().describe('Filter by planned replacement year'),
|
|
690
|
+
}, async (params) => {
|
|
691
|
+
try {
|
|
692
|
+
const result = await smartList(client, 'asset-replacement-plans', params);
|
|
693
|
+
return formatResult(result);
|
|
694
|
+
}
|
|
695
|
+
catch (err) {
|
|
696
|
+
return formatError(err);
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
server.tool('get_asset_replacement_plan', 'Get a single asset replacement plan by ID.', { id: uuidParam.describe('Replacement plan ID') }, async ({ id }) => {
|
|
700
|
+
try {
|
|
701
|
+
const result = await client.getOne('asset-replacement-plans', id);
|
|
702
|
+
return formatResult(result);
|
|
703
|
+
}
|
|
704
|
+
catch (err) {
|
|
705
|
+
return formatError(err);
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
// ============================================================
|
|
709
|
+
// Asset Risk History
|
|
710
|
+
// ============================================================
|
|
711
|
+
server.tool('list_asset_risk_history', 'List asset risk assessment history. Shows risk scores, condition scores, and trigger events over time.', {
|
|
712
|
+
...paginationSchema,
|
|
713
|
+
asset_id: z.string().uuid().optional().describe('Filter by asset ID'),
|
|
714
|
+
trigger_event: z.enum(['maintenance', 'inspection', 'manual_update', 'scheduled']).optional().describe('Filter by trigger event type'),
|
|
715
|
+
}, async (params) => {
|
|
716
|
+
try {
|
|
717
|
+
const result = await smartList(client, 'asset-risk-history', params);
|
|
718
|
+
return formatResult(result);
|
|
719
|
+
}
|
|
720
|
+
catch (err) {
|
|
721
|
+
return formatError(err);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
server.tool('get_asset_risk_history_entry', 'Get a single asset risk history entry by ID.', { id: uuidParam.describe('Risk history entry ID') }, async ({ id }) => {
|
|
725
|
+
try {
|
|
726
|
+
const result = await client.getOne('asset-risk-history', id);
|
|
727
|
+
return formatResult(result);
|
|
728
|
+
}
|
|
729
|
+
catch (err) {
|
|
730
|
+
return formatError(err);
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
// ============================================================
|
|
734
|
+
// Work Order Comments
|
|
735
|
+
// ============================================================
|
|
736
|
+
server.tool('list_work_order_comments', 'List comments on work orders. Filter by work_order_id to get comments for a specific work order.', {
|
|
737
|
+
...paginationSchema,
|
|
738
|
+
work_order_id: z.string().uuid().optional().describe('Filter by work order ID'),
|
|
739
|
+
}, async (params) => {
|
|
740
|
+
try {
|
|
741
|
+
const result = await smartList(client, 'work-order-comments', params);
|
|
742
|
+
return formatResult(result);
|
|
743
|
+
}
|
|
744
|
+
catch (err) {
|
|
745
|
+
return formatError(err);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
server.tool('get_work_order_comment', 'Get a single work order comment by ID.', { id: uuidParam.describe('Work order comment ID') }, async ({ id }) => {
|
|
749
|
+
try {
|
|
750
|
+
const result = await client.getOne('work-order-comments', id);
|
|
751
|
+
return formatResult(result);
|
|
752
|
+
}
|
|
753
|
+
catch (err) {
|
|
754
|
+
return formatError(err);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
// ============================================================
|
|
758
|
+
// Project Tasks
|
|
759
|
+
// ============================================================
|
|
760
|
+
server.tool('list_project_tasks', 'List project tasks (work breakdown structure). Filter by project, phase, status, or priority.', {
|
|
761
|
+
...searchSchema,
|
|
762
|
+
...paginationSchema,
|
|
763
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
764
|
+
phase_id: z.string().uuid().optional().describe('Filter by phase ID'),
|
|
765
|
+
status: z.enum(['todo', 'in_progress', 'completed', 'blocked', 'cancelled']).optional().describe('Filter by task status'),
|
|
766
|
+
priority: z.enum(['low', 'medium', 'high', 'critical']).optional().describe('Filter by priority'),
|
|
767
|
+
}, async (params) => {
|
|
768
|
+
try {
|
|
769
|
+
const result = await smartList(client, 'project-tasks', params);
|
|
770
|
+
return formatResult(result);
|
|
771
|
+
}
|
|
772
|
+
catch (err) {
|
|
773
|
+
return formatError(err);
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
server.tool('get_project_task', 'Get a single project task by ID, including cost and hour tracking.', { id: uuidParam.describe('Project task ID') }, async ({ id }) => {
|
|
777
|
+
try {
|
|
778
|
+
const result = await client.getOne('project-tasks', id);
|
|
779
|
+
return formatResult(result);
|
|
780
|
+
}
|
|
781
|
+
catch (err) {
|
|
782
|
+
return formatError(err);
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
// ============================================================
|
|
786
|
+
// Project Milestones
|
|
787
|
+
// ============================================================
|
|
788
|
+
server.tool('list_project_milestones', 'List project milestones. Filter by project or status (pending, completed, missed, at_risk).', {
|
|
789
|
+
...searchSchema,
|
|
790
|
+
...paginationSchema,
|
|
791
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
792
|
+
status: z.enum(['pending', 'completed', 'missed', 'at_risk']).optional().describe('Filter by milestone status'),
|
|
793
|
+
}, async (params) => {
|
|
794
|
+
try {
|
|
795
|
+
const result = await smartList(client, 'project-milestones', params);
|
|
796
|
+
return formatResult(result);
|
|
797
|
+
}
|
|
798
|
+
catch (err) {
|
|
799
|
+
return formatError(err);
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
server.tool('get_project_milestone', 'Get a single project milestone by ID.', { id: uuidParam.describe('Project milestone ID') }, async ({ id }) => {
|
|
803
|
+
try {
|
|
804
|
+
const result = await client.getOne('project-milestones', id);
|
|
805
|
+
return formatResult(result);
|
|
806
|
+
}
|
|
807
|
+
catch (err) {
|
|
808
|
+
return formatError(err);
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
// ============================================================
|
|
812
|
+
// Project Phases
|
|
813
|
+
// ============================================================
|
|
814
|
+
server.tool('list_project_phases', 'List project phases. Filter by project or status (pending, in_progress, completed, skipped).', {
|
|
815
|
+
...paginationSchema,
|
|
816
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
817
|
+
status: z.enum(['pending', 'in_progress', 'completed', 'skipped']).optional().describe('Filter by phase status'),
|
|
818
|
+
}, async (params) => {
|
|
819
|
+
try {
|
|
820
|
+
const result = await smartList(client, 'project-phases', params);
|
|
821
|
+
return formatResult(result);
|
|
822
|
+
}
|
|
823
|
+
catch (err) {
|
|
824
|
+
return formatError(err);
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
server.tool('get_project_phase', 'Get a single project phase by ID.', { id: uuidParam.describe('Project phase ID') }, async ({ id }) => {
|
|
828
|
+
try {
|
|
829
|
+
const result = await client.getOne('project-phases', id);
|
|
830
|
+
return formatResult(result);
|
|
831
|
+
}
|
|
832
|
+
catch (err) {
|
|
833
|
+
return formatError(err);
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
// ============================================================
|
|
837
|
+
// Project Budget Items
|
|
838
|
+
// ============================================================
|
|
839
|
+
server.tool('list_project_budget_items', 'List project budget line items (labor, materials, equipment, subcontractors, permits, contingency, other).', {
|
|
840
|
+
...paginationSchema,
|
|
841
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
842
|
+
category: z.enum(['labor', 'materials', 'equipment', 'subcontractors', 'permits', 'contingency', 'other']).optional().describe('Filter by budget category'),
|
|
843
|
+
}, async (params) => {
|
|
844
|
+
try {
|
|
845
|
+
const result = await smartList(client, 'project-budget-items', params);
|
|
846
|
+
return formatResult(result);
|
|
847
|
+
}
|
|
848
|
+
catch (err) {
|
|
849
|
+
return formatError(err);
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
server.tool('get_project_budget_item', 'Get a single project budget item by ID.', { id: uuidParam.describe('Budget item ID') }, async ({ id }) => {
|
|
853
|
+
try {
|
|
854
|
+
const result = await client.getOne('project-budget-items', id);
|
|
855
|
+
return formatResult(result);
|
|
856
|
+
}
|
|
857
|
+
catch (err) {
|
|
858
|
+
return formatError(err);
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
// ============================================================
|
|
862
|
+
// Project Time Entries
|
|
863
|
+
// ============================================================
|
|
864
|
+
server.tool('list_project_time_entries', 'List project time entries for labor tracking. Filter by project, task, or user.', {
|
|
865
|
+
...paginationSchema,
|
|
866
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
867
|
+
task_id: z.string().uuid().optional().describe('Filter by task ID'),
|
|
868
|
+
user_id: z.string().optional().describe('Filter by user ID'),
|
|
869
|
+
}, async (params) => {
|
|
870
|
+
try {
|
|
871
|
+
const result = await smartList(client, 'project-time-entries', params);
|
|
872
|
+
return formatResult(result);
|
|
873
|
+
}
|
|
874
|
+
catch (err) {
|
|
875
|
+
return formatError(err);
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
server.tool('get_project_time_entry', 'Get a single project time entry by ID.', { id: uuidParam.describe('Time entry ID') }, async ({ id }) => {
|
|
879
|
+
try {
|
|
880
|
+
const result = await client.getOne('project-time-entries', id);
|
|
881
|
+
return formatResult(result);
|
|
882
|
+
}
|
|
883
|
+
catch (err) {
|
|
884
|
+
return formatError(err);
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
// ============================================================
|
|
888
|
+
// Project Comments
|
|
889
|
+
// ============================================================
|
|
890
|
+
server.tool('list_project_comments', 'List comments on projects. Supports threaded replies via parent_id.', {
|
|
891
|
+
...paginationSchema,
|
|
892
|
+
project_id: z.string().uuid().optional().describe('Filter by project ID'),
|
|
893
|
+
}, async (params) => {
|
|
894
|
+
try {
|
|
895
|
+
const result = await smartList(client, 'project-comments', params);
|
|
896
|
+
return formatResult(result);
|
|
897
|
+
}
|
|
898
|
+
catch (err) {
|
|
899
|
+
return formatError(err);
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
server.tool('get_project_comment', 'Get a single project comment by ID.', { id: uuidParam.describe('Project comment ID') }, async ({ id }) => {
|
|
903
|
+
try {
|
|
904
|
+
const result = await client.getOne('project-comments', id);
|
|
905
|
+
return formatResult(result);
|
|
906
|
+
}
|
|
907
|
+
catch (err) {
|
|
908
|
+
return formatError(err);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
// ============================================================
|
|
912
|
+
// Compliance Records
|
|
913
|
+
// ============================================================
|
|
914
|
+
server.tool('list_compliance_records', 'List compliance records — audit trail of completed compliance checks linked to work orders and PM schedules.', {
|
|
915
|
+
...paginationSchema,
|
|
916
|
+
compliance_item_id: z.string().uuid().optional().describe('Filter by compliance item ID'),
|
|
917
|
+
work_order_id: z.string().uuid().optional().describe('Filter by work order ID'),
|
|
918
|
+
}, async (params) => {
|
|
919
|
+
try {
|
|
920
|
+
const result = await smartList(client, 'compliance-records', params);
|
|
921
|
+
return formatResult(result);
|
|
922
|
+
}
|
|
923
|
+
catch (err) {
|
|
924
|
+
return formatError(err);
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
server.tool('get_compliance_record', 'Get a single compliance record by ID.', { id: uuidParam.describe('Compliance record ID') }, async ({ id }) => {
|
|
928
|
+
try {
|
|
929
|
+
const result = await client.getOne('compliance-records', id);
|
|
930
|
+
return formatResult(result);
|
|
931
|
+
}
|
|
932
|
+
catch (err) {
|
|
933
|
+
return formatError(err);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
// ============================================================
|
|
937
|
+
// Site FCI History
|
|
938
|
+
// ============================================================
|
|
939
|
+
server.tool('list_site_fci_history', 'List Facility Condition Index (FCI) history for sites. Track FCI trends over time.', {
|
|
940
|
+
...paginationSchema,
|
|
941
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
942
|
+
}, async (params) => {
|
|
943
|
+
try {
|
|
944
|
+
const result = await smartList(client, 'site-fci-history', params);
|
|
945
|
+
return formatResult(result);
|
|
946
|
+
}
|
|
947
|
+
catch (err) {
|
|
948
|
+
return formatError(err);
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
server.tool('get_site_fci_history_entry', 'Get a single site FCI history entry by ID.', { id: uuidParam.describe('FCI history entry ID') }, async ({ id }) => {
|
|
952
|
+
try {
|
|
953
|
+
const result = await client.getOne('site-fci-history', id);
|
|
954
|
+
return formatResult(result);
|
|
955
|
+
}
|
|
956
|
+
catch (err) {
|
|
957
|
+
return formatError(err);
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
// ============================================================
|
|
961
|
+
// Dashboard Snapshots
|
|
962
|
+
// ============================================================
|
|
963
|
+
server.tool('list_dashboard_snapshots', 'List monthly dashboard snapshots with aggregate stats: asset counts, condition scores, work order metrics, and CRV totals.', {
|
|
964
|
+
...paginationSchema,
|
|
965
|
+
year: z.number().int().optional().describe('Filter by snapshot year (e.g. 2026)'),
|
|
966
|
+
month: z.number().int().min(1).max(12).optional().describe('Filter by snapshot month (1-12)'),
|
|
967
|
+
}, async (params) => {
|
|
968
|
+
try {
|
|
969
|
+
const result = await smartList(client, 'dashboard-snapshots', params);
|
|
970
|
+
return formatResult(result);
|
|
971
|
+
}
|
|
972
|
+
catch (err) {
|
|
973
|
+
return formatError(err);
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
server.tool('get_dashboard_snapshot', 'Get a single dashboard snapshot by ID.', { id: uuidParam.describe('Dashboard snapshot ID') }, async ({ id }) => {
|
|
977
|
+
try {
|
|
978
|
+
const result = await client.getOne('dashboard-snapshots', id);
|
|
979
|
+
return formatResult(result);
|
|
980
|
+
}
|
|
981
|
+
catch (err) {
|
|
982
|
+
return formatError(err);
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
// ============================================================
|
|
986
|
+
// Vendor Site Assignments
|
|
987
|
+
// ============================================================
|
|
988
|
+
server.tool('list_vendor_site_assignments', 'List vendor-to-site assignments showing which vendors serve which sites.', {
|
|
989
|
+
...paginationSchema,
|
|
990
|
+
vendor_id: z.string().uuid().optional().describe('Filter by vendor ID'),
|
|
991
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
992
|
+
}, async (params) => {
|
|
993
|
+
try {
|
|
994
|
+
const result = await smartList(client, 'vendor-site-assignments', params);
|
|
995
|
+
return formatResult(result);
|
|
996
|
+
}
|
|
997
|
+
catch (err) {
|
|
998
|
+
return formatError(err);
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
server.tool('get_vendor_site_assignment', 'Get a single vendor site assignment by ID, including vendor and site names.', { id: uuidParam.describe('Vendor site assignment ID') }, async ({ id }) => {
|
|
1002
|
+
try {
|
|
1003
|
+
const result = await client.getOne('vendor-site-assignments', id);
|
|
1004
|
+
return formatResult(result);
|
|
1005
|
+
}
|
|
1006
|
+
catch (err) {
|
|
1007
|
+
return formatError(err);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
// ============================================================
|
|
1011
|
+
// Contract Sites
|
|
1012
|
+
// ============================================================
|
|
1013
|
+
server.tool('list_contract_sites', 'List contract-to-site mappings showing which contracts cover which sites. No single-record lookup (composite key).', {
|
|
1014
|
+
...paginationSchema,
|
|
1015
|
+
contract_id: z.string().uuid().optional().describe('Filter by contract ID'),
|
|
1016
|
+
site_id: z.string().uuid().optional().describe('Filter by site ID'),
|
|
1017
|
+
}, async (params) => {
|
|
1018
|
+
try {
|
|
1019
|
+
const result = await smartList(client, 'contract-sites', params);
|
|
1020
|
+
return formatResult(result);
|
|
1021
|
+
}
|
|
1022
|
+
catch (err) {
|
|
1023
|
+
return formatError(err);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
// ============================================================
|
|
1027
|
+
// Custom Field Definitions
|
|
1028
|
+
// ============================================================
|
|
1029
|
+
server.tool('list_custom_field_definitions', 'List custom field definitions configured for this tenant. Filter by entity type (e.g. asset, work_order) or field type.', {
|
|
1030
|
+
...paginationSchema,
|
|
1031
|
+
entity_type: z.string().max(100).optional().describe('Filter by entity type (e.g. asset, work_order)'),
|
|
1032
|
+
field_type: z.enum(['text', 'number', 'date', 'boolean', 'select']).optional().describe('Filter by field type'),
|
|
1033
|
+
}, async (params) => {
|
|
1034
|
+
try {
|
|
1035
|
+
const result = await smartList(client, 'custom-field-definitions', params);
|
|
1036
|
+
return formatResult(result);
|
|
1037
|
+
}
|
|
1038
|
+
catch (err) {
|
|
1039
|
+
return formatError(err);
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
server.tool('get_custom_field_definition', 'Get a single custom field definition by ID.', { id: uuidParam.describe('Custom field definition ID') }, async ({ id }) => {
|
|
1043
|
+
try {
|
|
1044
|
+
const result = await client.getOne('custom-field-definitions', id);
|
|
1045
|
+
return formatResult(result);
|
|
1046
|
+
}
|
|
1047
|
+
catch (err) {
|
|
1048
|
+
return formatError(err);
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
// ============================================================
|
|
1052
|
+
// Custom Field Values
|
|
1053
|
+
// ============================================================
|
|
1054
|
+
server.tool('list_custom_field_values', 'List custom field values. Filter by entity_id to get all custom fields for a specific record, or by field_definition_id.', {
|
|
1055
|
+
...paginationSchema,
|
|
1056
|
+
entity_id: z.string().uuid().optional().describe('Filter by entity ID (e.g. asset ID, work order ID)'),
|
|
1057
|
+
field_definition_id: z.string().uuid().optional().describe('Filter by field definition ID'),
|
|
1058
|
+
}, async (params) => {
|
|
1059
|
+
try {
|
|
1060
|
+
const result = await smartList(client, 'custom-field-values', params);
|
|
1061
|
+
return formatResult(result);
|
|
1062
|
+
}
|
|
1063
|
+
catch (err) {
|
|
1064
|
+
return formatError(err);
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
server.tool('get_custom_field_value', 'Get a single custom field value by ID.', { id: uuidParam.describe('Custom field value ID') }, async ({ id }) => {
|
|
1068
|
+
try {
|
|
1069
|
+
const result = await client.getOne('custom-field-values', id);
|
|
1070
|
+
return formatResult(result);
|
|
1071
|
+
}
|
|
1072
|
+
catch (err) {
|
|
1073
|
+
return formatError(err);
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1076
|
+
// ============================================================
|
|
1077
|
+
// Part Categories
|
|
1078
|
+
// ============================================================
|
|
1079
|
+
server.tool('list_part_categories', 'List part categories used to classify inventory parts.', {
|
|
1080
|
+
...searchSchema,
|
|
1081
|
+
...paginationSchema,
|
|
1082
|
+
}, async (params) => {
|
|
1083
|
+
try {
|
|
1084
|
+
const result = await smartList(client, 'part-categories', params);
|
|
1085
|
+
return formatResult(result);
|
|
1086
|
+
}
|
|
1087
|
+
catch (err) {
|
|
1088
|
+
return formatError(err);
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
server.tool('get_part_category', 'Get a single part category by ID.', { id: uuidParam.describe('Part category ID') }, async ({ id }) => {
|
|
1092
|
+
try {
|
|
1093
|
+
const result = await client.getOne('part-categories', id);
|
|
1094
|
+
return formatResult(result);
|
|
1095
|
+
}
|
|
1096
|
+
catch (err) {
|
|
1097
|
+
return formatError(err);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
300
1100
|
}
|
|
301
1101
|
//# sourceMappingURL=tools.js.map
|