@assetlab/mcp-server 1.5.1 → 1.7.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 +34 -2
- package/dist/oauth.js +38 -12
- package/dist/oauth.js.map +1 -1
- package/dist/tools-write.js +543 -21
- package/dist/tools-write.js.map +1 -1
- package/dist/tools.js +259 -1
- package/dist/tools.js.map +1 -1
- package/package.json +7 -3
package/dist/tools-write.js
CHANGED
|
@@ -125,11 +125,11 @@ export function registerWriteTools(server, client) {
|
|
|
125
125
|
salvage_value_percentage: z.number().min(0).max(100).optional().describe('Salvage value percentage (0-100)'),
|
|
126
126
|
consequence_of_failure_score: z.number().int().min(0).optional().describe('Consequence of failure score'),
|
|
127
127
|
likelihood_of_failure_score: z.number().int().min(0).optional().describe('Likelihood of failure score'),
|
|
128
|
-
safety_impact: z.
|
|
129
|
-
service_impact: z.
|
|
130
|
-
environmental_impact: z.
|
|
131
|
-
regulatory_impact: z.
|
|
132
|
-
reputation_impact: z.
|
|
128
|
+
safety_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Safety impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
129
|
+
service_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Service impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
130
|
+
environmental_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Environmental impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
131
|
+
regulatory_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Regulatory impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
132
|
+
reputation_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Reputation impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
133
133
|
}, async (params) => {
|
|
134
134
|
try {
|
|
135
135
|
const result = await client.create('assets', buildBody(params));
|
|
@@ -170,11 +170,11 @@ export function registerWriteTools(server, client) {
|
|
|
170
170
|
salvage_value_percentage: z.number().min(0).max(100).optional().describe('Salvage value percentage (0-100)'),
|
|
171
171
|
consequence_of_failure_score: z.number().int().min(0).optional().describe('Consequence of failure score'),
|
|
172
172
|
likelihood_of_failure_score: z.number().int().min(0).optional().describe('Likelihood of failure score'),
|
|
173
|
-
safety_impact: z.
|
|
174
|
-
service_impact: z.
|
|
175
|
-
environmental_impact: z.
|
|
176
|
-
regulatory_impact: z.
|
|
177
|
-
reputation_impact: z.
|
|
173
|
+
safety_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Safety impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
174
|
+
service_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Service impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
175
|
+
environmental_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Environmental impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
176
|
+
regulatory_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Regulatory impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
177
|
+
reputation_impact: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).optional().describe('Reputation impact level (LOW, MEDIUM, HIGH, CRITICAL)'),
|
|
178
178
|
}, async ({ id, ...rest }) => {
|
|
179
179
|
try {
|
|
180
180
|
const result = await client.update('assets', id, buildBody(rest));
|
|
@@ -259,8 +259,8 @@ export function registerWriteTools(server, client) {
|
|
|
259
259
|
state: z.string().max(100).optional().describe('State/province'),
|
|
260
260
|
country: z.string().max(100).optional().describe('Country'),
|
|
261
261
|
status: z.string().max(50).optional().describe('Vendor status'),
|
|
262
|
-
|
|
263
|
-
website: z.string().max(500).optional().describe('Website URL'),
|
|
262
|
+
categories: z.array(z.string().max(100)).optional().describe('Vendor categories (e.g. ["HVAC", "Plumbing"])'),
|
|
263
|
+
website: z.string().max(500).optional().describe('Website URL (protocol and www prefix are stripped automatically)'),
|
|
264
264
|
description: z.string().optional().describe('Description'),
|
|
265
265
|
}, async (params) => {
|
|
266
266
|
try {
|
|
@@ -282,8 +282,8 @@ export function registerWriteTools(server, client) {
|
|
|
282
282
|
state: z.string().max(100).optional().describe('State/province'),
|
|
283
283
|
country: z.string().max(100).optional().describe('Country'),
|
|
284
284
|
status: z.string().max(50).optional().describe('Vendor status'),
|
|
285
|
-
|
|
286
|
-
website: z.string().max(500).optional().describe('Website URL'),
|
|
285
|
+
categories: z.array(z.string().max(100)).optional().describe('Vendor categories (e.g. ["HVAC", "Plumbing"])'),
|
|
286
|
+
website: z.string().max(500).optional().describe('Website URL (protocol and www prefix are stripped automatically)'),
|
|
287
287
|
description: z.string().optional().describe('Description'),
|
|
288
288
|
}, async ({ id, ...rest }) => {
|
|
289
289
|
try {
|
|
@@ -485,6 +485,11 @@ export function registerWriteTools(server, client) {
|
|
|
485
485
|
asset_ids: z.array(z.string().uuid()).optional().describe('Array of asset IDs'),
|
|
486
486
|
system_ids: z.array(z.string().uuid()).optional().describe('Array of system IDs'),
|
|
487
487
|
location_ids: z.array(z.string().uuid()).optional().describe('Array of location IDs'),
|
|
488
|
+
tasks: z.array(z.object({
|
|
489
|
+
id: z.string().describe('Unique task ID (use a random string)'),
|
|
490
|
+
description: z.string().describe('Task description'),
|
|
491
|
+
completed: z.boolean().describe('Whether the task is completed'),
|
|
492
|
+
})).optional().describe('Checklist of tasks for this PM schedule'),
|
|
488
493
|
}, async (params) => {
|
|
489
494
|
try {
|
|
490
495
|
const result = await client.create('pm-schedules', buildBody(params));
|
|
@@ -519,6 +524,11 @@ export function registerWriteTools(server, client) {
|
|
|
519
524
|
asset_ids: z.array(z.string().uuid()).optional().describe('Array of asset IDs'),
|
|
520
525
|
system_ids: z.array(z.string().uuid()).optional().describe('Array of system IDs'),
|
|
521
526
|
location_ids: z.array(z.string().uuid()).optional().describe('Array of location IDs'),
|
|
527
|
+
tasks: z.array(z.object({
|
|
528
|
+
id: z.string().describe('Unique task ID'),
|
|
529
|
+
description: z.string().describe('Task description'),
|
|
530
|
+
completed: z.boolean().describe('Whether the task is completed'),
|
|
531
|
+
})).optional().describe('Checklist of tasks for this PM schedule'),
|
|
522
532
|
}, async ({ id, ...rest }) => {
|
|
523
533
|
try {
|
|
524
534
|
const result = await client.update('pm-schedules', id, buildBody(rest));
|
|
@@ -545,7 +555,7 @@ export function registerWriteTools(server, client) {
|
|
|
545
555
|
status: z.string().max(100).describe('Project status (required)'),
|
|
546
556
|
start_date: z.string().describe('Start date (ISO 8601, required)'),
|
|
547
557
|
project_code: z.string().max(100).optional().describe('Project code'),
|
|
548
|
-
project_type: z.
|
|
558
|
+
project_type: z.enum(['capital', 'maintenance', 'repair', 'upgrade', 'new_construction', 'renovation', 'deferred_maintenance', 'other']).optional().describe('Project type'),
|
|
549
559
|
current_phase: z.string().max(100).optional().describe('Current phase'),
|
|
550
560
|
description: z.string().optional().describe('Description'),
|
|
551
561
|
end_date: z.string().optional().describe('End date (ISO 8601)'),
|
|
@@ -569,7 +579,7 @@ export function registerWriteTools(server, client) {
|
|
|
569
579
|
status: z.string().max(100).optional().describe('Project status'),
|
|
570
580
|
start_date: z.string().optional().describe('Start date (ISO 8601)'),
|
|
571
581
|
project_code: z.string().max(100).optional().describe('Project code'),
|
|
572
|
-
project_type: z.
|
|
582
|
+
project_type: z.enum(['capital', 'maintenance', 'repair', 'upgrade', 'new_construction', 'renovation', 'deferred_maintenance', 'other']).optional().describe('Project type'),
|
|
573
583
|
current_phase: z.string().max(100).optional().describe('Current phase'),
|
|
574
584
|
description: z.string().optional().describe('Description'),
|
|
575
585
|
end_date: z.string().optional().describe('End date (ISO 8601)'),
|
|
@@ -981,7 +991,7 @@ export function registerWriteTools(server, client) {
|
|
|
981
991
|
// 18. Asset Costs (scope: asset_costs)
|
|
982
992
|
// ============================================================
|
|
983
993
|
server.tool('create_asset_cost', 'Create a new asset cost entry. Requires asset_costs:write scope.', {
|
|
984
|
-
category: z.enum(['Repair', 'PM', 'Operation', 'Replacement', 'Decommission']).describe('Cost category (required)'),
|
|
994
|
+
category: z.enum(['Repair', 'PM', 'Operation', 'Replacement', 'Decommission', 'Other']).describe('Cost category (required)'),
|
|
985
995
|
amount: z.number().min(0).describe('Cost amount (required)'),
|
|
986
996
|
cost_date: z.string().describe('Cost date (ISO 8601, required)'),
|
|
987
997
|
asset_id: z.string().uuid().optional().describe('Asset ID'),
|
|
@@ -989,7 +999,6 @@ export function registerWriteTools(server, client) {
|
|
|
989
999
|
building_id: z.string().uuid().optional().describe('Building ID'),
|
|
990
1000
|
work_order_id: z.string().uuid().optional().describe('Work order ID'),
|
|
991
1001
|
description: z.string().optional().describe('Description'),
|
|
992
|
-
vendor_id: z.string().uuid().optional().describe('Vendor ID'),
|
|
993
1002
|
}, async (params) => {
|
|
994
1003
|
try {
|
|
995
1004
|
const result = await client.create('asset-costs', buildBody(params));
|
|
@@ -1001,7 +1010,7 @@ export function registerWriteTools(server, client) {
|
|
|
1001
1010
|
});
|
|
1002
1011
|
server.tool('update_asset_cost', 'Update an existing asset cost entry by ID. Requires asset_costs:write scope.', {
|
|
1003
1012
|
id: z.string().uuid().describe('Asset cost ID'),
|
|
1004
|
-
category: z.enum(['Repair', 'PM', 'Operation', 'Replacement', 'Decommission']).optional().describe('Cost category'),
|
|
1013
|
+
category: z.enum(['Repair', 'PM', 'Operation', 'Replacement', 'Decommission', 'Other']).optional().describe('Cost category'),
|
|
1005
1014
|
amount: z.number().min(0).optional().describe('Cost amount'),
|
|
1006
1015
|
cost_date: z.string().optional().describe('Cost date (ISO 8601)'),
|
|
1007
1016
|
asset_id: z.string().uuid().optional().describe('Asset ID'),
|
|
@@ -1009,7 +1018,6 @@ export function registerWriteTools(server, client) {
|
|
|
1009
1018
|
building_id: z.string().uuid().optional().describe('Building ID'),
|
|
1010
1019
|
work_order_id: z.string().uuid().optional().describe('Work order ID'),
|
|
1011
1020
|
description: z.string().optional().describe('Description'),
|
|
1012
|
-
vendor_id: z.string().uuid().optional().describe('Vendor ID'),
|
|
1013
1021
|
}, async ({ id, ...rest }) => {
|
|
1014
1022
|
try {
|
|
1015
1023
|
const result = await client.update('asset-costs', id, buildBody(rest));
|
|
@@ -1935,6 +1943,388 @@ export function registerWriteTools(server, client) {
|
|
|
1935
1943
|
}
|
|
1936
1944
|
});
|
|
1937
1945
|
// ============================================================
|
|
1946
|
+
// Upload URLs
|
|
1947
|
+
// ============================================================
|
|
1948
|
+
server.tool('create_upload_url', 'Generate a signed upload URL for uploading a file to AssetLab storage. Returns a signed_url to PUT the file to, plus the path to reference when creating a document record. Requires upload_urls:write scope.', {
|
|
1949
|
+
bucket: z.enum(['documents', 'attachments', 'project-documents', 'contract-documents']).describe('Storage bucket (required)'),
|
|
1950
|
+
file_name: z.string().min(1).max(500).describe('File name including extension (required)'),
|
|
1951
|
+
}, async (params) => {
|
|
1952
|
+
try {
|
|
1953
|
+
const result = await client.create('upload-urls', buildBody(params));
|
|
1954
|
+
return formatResult(result);
|
|
1955
|
+
}
|
|
1956
|
+
catch (err) {
|
|
1957
|
+
return formatError(err);
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
// ============================================================
|
|
1961
|
+
// Asset Documents (scope: asset_documents)
|
|
1962
|
+
// ============================================================
|
|
1963
|
+
server.tool('create_asset_document', 'Create an asset document record (after uploading the file via create_upload_url). Requires asset_documents:write scope.', {
|
|
1964
|
+
name: z.string().min(1).max(500).describe('Document name (required)'),
|
|
1965
|
+
file_path: z.string().min(1).max(2000).describe('Storage path from upload URL response (required)'),
|
|
1966
|
+
asset_id: z.string().uuid().describe('Asset ID this document belongs to (required)'),
|
|
1967
|
+
category: z.enum(['om', 'commissioning', 'warranty', 'installation', 'specification', 'other']).optional().describe('Document category'),
|
|
1968
|
+
description: z.string().optional().describe('Description'),
|
|
1969
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
1970
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
1971
|
+
user_id: z.string().max(200).optional().describe('Uploader user ID'),
|
|
1972
|
+
}, async (params) => {
|
|
1973
|
+
try {
|
|
1974
|
+
const result = await client.create('asset-documents', buildBody(params));
|
|
1975
|
+
return formatResult(result);
|
|
1976
|
+
}
|
|
1977
|
+
catch (err) {
|
|
1978
|
+
return formatError(err);
|
|
1979
|
+
}
|
|
1980
|
+
});
|
|
1981
|
+
server.tool('update_asset_document', 'Update an asset document by ID. Requires asset_documents:write scope.', {
|
|
1982
|
+
id: z.string().uuid().describe('Asset document ID'),
|
|
1983
|
+
name: z.string().min(1).max(500).optional().describe('Document name'),
|
|
1984
|
+
file_path: z.string().max(2000).optional().describe('Storage path'),
|
|
1985
|
+
asset_id: z.string().uuid().optional().describe('Asset ID'),
|
|
1986
|
+
category: z.enum(['om', 'commissioning', 'warranty', 'installation', 'specification', 'other']).optional().describe('Document category'),
|
|
1987
|
+
description: z.string().optional().describe('Description'),
|
|
1988
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
1989
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
1990
|
+
user_id: z.string().max(200).optional().describe('Uploader user ID'),
|
|
1991
|
+
}, async ({ id, ...rest }) => {
|
|
1992
|
+
try {
|
|
1993
|
+
const result = await client.update('asset-documents', id, buildBody(rest));
|
|
1994
|
+
return formatResult(result);
|
|
1995
|
+
}
|
|
1996
|
+
catch (err) {
|
|
1997
|
+
return formatError(err);
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
server.tool('delete_asset_document', 'Delete an asset document by ID. Requires asset_documents:write scope.', { id: z.string().uuid().describe('Asset document ID') }, async ({ id }) => {
|
|
2001
|
+
try {
|
|
2002
|
+
const result = await client.remove('asset-documents', id);
|
|
2003
|
+
return formatResult(result);
|
|
2004
|
+
}
|
|
2005
|
+
catch (err) {
|
|
2006
|
+
return formatError(err);
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
// ============================================================
|
|
2010
|
+
// Attachments (scope: attachments)
|
|
2011
|
+
// ============================================================
|
|
2012
|
+
server.tool('create_attachment', 'Create an attachment record linked to a work order, work request, PM schedule, or PM template. Exactly one parent ID must be provided. Requires attachments:write scope.', {
|
|
2013
|
+
file_url: z.string().min(1).max(2000).describe('File URL / storage path (required)'),
|
|
2014
|
+
file_name: z.string().min(1).max(500).describe('File name (required)'),
|
|
2015
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2016
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2017
|
+
uploaded_by: z.string().max(200).optional().describe('Uploader user ID'),
|
|
2018
|
+
description: z.string().optional().describe('Description'),
|
|
2019
|
+
work_order_id: z.string().uuid().optional().describe('Work order ID (exactly one parent required)'),
|
|
2020
|
+
work_request_id: z.string().uuid().optional().describe('Work request ID (exactly one parent required)'),
|
|
2021
|
+
pm_schedule_id: z.string().uuid().optional().describe('PM schedule ID (exactly one parent required)'),
|
|
2022
|
+
pm_template_id: z.string().uuid().optional().describe('PM template ID (exactly one parent required)'),
|
|
2023
|
+
}, async (params) => {
|
|
2024
|
+
try {
|
|
2025
|
+
const result = await client.create('attachments', buildBody(params));
|
|
2026
|
+
return formatResult(result);
|
|
2027
|
+
}
|
|
2028
|
+
catch (err) {
|
|
2029
|
+
return formatError(err);
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
server.tool('update_attachment', 'Update an attachment by ID. Requires attachments:write scope.', {
|
|
2033
|
+
id: z.string().uuid().describe('Attachment ID'),
|
|
2034
|
+
file_url: z.string().max(2000).optional().describe('File URL / storage path'),
|
|
2035
|
+
file_name: z.string().max(500).optional().describe('File name'),
|
|
2036
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2037
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2038
|
+
uploaded_by: z.string().max(200).optional().describe('Uploader user ID'),
|
|
2039
|
+
description: z.string().optional().describe('Description'),
|
|
2040
|
+
work_order_id: z.string().uuid().optional().describe('Work order ID'),
|
|
2041
|
+
work_request_id: z.string().uuid().optional().describe('Work request ID'),
|
|
2042
|
+
pm_schedule_id: z.string().uuid().optional().describe('PM schedule ID'),
|
|
2043
|
+
pm_template_id: z.string().uuid().optional().describe('PM template ID'),
|
|
2044
|
+
}, async ({ id, ...rest }) => {
|
|
2045
|
+
try {
|
|
2046
|
+
const result = await client.update('attachments', id, buildBody(rest));
|
|
2047
|
+
return formatResult(result);
|
|
2048
|
+
}
|
|
2049
|
+
catch (err) {
|
|
2050
|
+
return formatError(err);
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
2053
|
+
server.tool('delete_attachment', 'Delete an attachment by ID. Requires attachments:write scope.', { id: z.string().uuid().describe('Attachment ID') }, async ({ id }) => {
|
|
2054
|
+
try {
|
|
2055
|
+
const result = await client.remove('attachments', id);
|
|
2056
|
+
return formatResult(result);
|
|
2057
|
+
}
|
|
2058
|
+
catch (err) {
|
|
2059
|
+
return formatError(err);
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
// ============================================================
|
|
2063
|
+
// Project Documents (scope: project_documents)
|
|
2064
|
+
// ============================================================
|
|
2065
|
+
server.tool('create_project_document', 'Create a project document record. Requires project_documents:write scope.', {
|
|
2066
|
+
project_id: z.string().uuid().describe('Project ID (required)'),
|
|
2067
|
+
name: z.string().min(1).max(500).describe('Document name (required)'),
|
|
2068
|
+
file_path: z.string().min(1).max(2000).describe('Storage path from upload URL response (required)'),
|
|
2069
|
+
uploaded_by: z.string().min(1).max(200).describe('Uploader user ID (required)'),
|
|
2070
|
+
folder_id: z.string().uuid().optional().describe('Folder ID'),
|
|
2071
|
+
description: z.string().optional().describe('Description'),
|
|
2072
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2073
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2074
|
+
}, async (params) => {
|
|
2075
|
+
try {
|
|
2076
|
+
const result = await client.create('project-documents', buildBody(params));
|
|
2077
|
+
return formatResult(result);
|
|
2078
|
+
}
|
|
2079
|
+
catch (err) {
|
|
2080
|
+
return formatError(err);
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
server.tool('update_project_document', 'Update a project document by ID. Requires project_documents:write scope.', {
|
|
2084
|
+
id: z.string().uuid().describe('Project document ID'),
|
|
2085
|
+
project_id: z.string().uuid().optional().describe('Project ID'),
|
|
2086
|
+
name: z.string().min(1).max(500).optional().describe('Document name'),
|
|
2087
|
+
file_path: z.string().max(2000).optional().describe('Storage path'),
|
|
2088
|
+
uploaded_by: z.string().max(200).optional().describe('Uploader user ID'),
|
|
2089
|
+
folder_id: z.string().uuid().optional().describe('Folder ID'),
|
|
2090
|
+
description: z.string().optional().describe('Description'),
|
|
2091
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2092
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2093
|
+
}, async ({ id, ...rest }) => {
|
|
2094
|
+
try {
|
|
2095
|
+
const result = await client.update('project-documents', id, buildBody(rest));
|
|
2096
|
+
return formatResult(result);
|
|
2097
|
+
}
|
|
2098
|
+
catch (err) {
|
|
2099
|
+
return formatError(err);
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
server.tool('delete_project_document', 'Delete a project document by ID. Requires project_documents:write scope.', { id: z.string().uuid().describe('Project document ID') }, async ({ id }) => {
|
|
2103
|
+
try {
|
|
2104
|
+
const result = await client.remove('project-documents', id);
|
|
2105
|
+
return formatResult(result);
|
|
2106
|
+
}
|
|
2107
|
+
catch (err) {
|
|
2108
|
+
return formatError(err);
|
|
2109
|
+
}
|
|
2110
|
+
});
|
|
2111
|
+
// ============================================================
|
|
2112
|
+
// Contract Documents (scope: contract_documents)
|
|
2113
|
+
// ============================================================
|
|
2114
|
+
server.tool('create_contract_document', 'Create a contract document record. Requires contract_documents:write scope.', {
|
|
2115
|
+
contract_id: z.string().uuid().describe('Contract ID (required)'),
|
|
2116
|
+
file_name: z.string().min(1).max(500).describe('File name (required)'),
|
|
2117
|
+
file_path: z.string().min(1).max(2000).describe('Storage path from upload URL response (required)'),
|
|
2118
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2119
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2120
|
+
uploaded_by: z.string().max(200).optional().describe('Uploader user ID'),
|
|
2121
|
+
}, async (params) => {
|
|
2122
|
+
try {
|
|
2123
|
+
const result = await client.create('contract-documents', buildBody(params));
|
|
2124
|
+
return formatResult(result);
|
|
2125
|
+
}
|
|
2126
|
+
catch (err) {
|
|
2127
|
+
return formatError(err);
|
|
2128
|
+
}
|
|
2129
|
+
});
|
|
2130
|
+
server.tool('update_contract_document', 'Update a contract document by ID. Requires contract_documents:write scope.', {
|
|
2131
|
+
id: z.string().uuid().describe('Contract document ID'),
|
|
2132
|
+
contract_id: z.string().uuid().optional().describe('Contract ID'),
|
|
2133
|
+
file_name: z.string().max(500).optional().describe('File name'),
|
|
2134
|
+
file_path: z.string().max(2000).optional().describe('Storage path'),
|
|
2135
|
+
file_size: z.number().min(0).optional().describe('File size in bytes'),
|
|
2136
|
+
file_type: z.string().max(200).optional().describe('MIME type'),
|
|
2137
|
+
uploaded_by: z.string().max(200).optional().describe('Uploader user ID'),
|
|
2138
|
+
}, async ({ id, ...rest }) => {
|
|
2139
|
+
try {
|
|
2140
|
+
const result = await client.update('contract-documents', id, buildBody(rest));
|
|
2141
|
+
return formatResult(result);
|
|
2142
|
+
}
|
|
2143
|
+
catch (err) {
|
|
2144
|
+
return formatError(err);
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
server.tool('delete_contract_document', 'Delete a contract document by ID. Requires contract_documents:write scope.', { id: z.string().uuid().describe('Contract document ID') }, async ({ id }) => {
|
|
2148
|
+
try {
|
|
2149
|
+
const result = await client.remove('contract-documents', id);
|
|
2150
|
+
return formatResult(result);
|
|
2151
|
+
}
|
|
2152
|
+
catch (err) {
|
|
2153
|
+
return formatError(err);
|
|
2154
|
+
}
|
|
2155
|
+
});
|
|
2156
|
+
// ============================================================
|
|
2157
|
+
// Project Team Members
|
|
2158
|
+
// ============================================================
|
|
2159
|
+
server.tool('create_project_team_member', 'Add a team member to a project. Requires project_team_members:write scope.', {
|
|
2160
|
+
project_id: z.string().uuid().describe('Project ID (required)'),
|
|
2161
|
+
user_id: z.string().min(1).max(200).describe('Clerk user ID (required)'),
|
|
2162
|
+
role: z.string().min(1).max(100).describe('Role on the project (required)'),
|
|
2163
|
+
responsibilities: z.string().optional().describe('Description of responsibilities'),
|
|
2164
|
+
start_date: z.string().optional().describe('Start date (ISO 8601)'),
|
|
2165
|
+
end_date: z.string().optional().describe('End date (ISO 8601)'),
|
|
2166
|
+
is_active: z.boolean().optional().describe('Whether member is currently active'),
|
|
2167
|
+
}, async (params) => {
|
|
2168
|
+
try {
|
|
2169
|
+
const result = await client.create('project-team-members', buildBody(params));
|
|
2170
|
+
return formatResult(result);
|
|
2171
|
+
}
|
|
2172
|
+
catch (err) {
|
|
2173
|
+
return formatError(err);
|
|
2174
|
+
}
|
|
2175
|
+
});
|
|
2176
|
+
server.tool('update_project_team_member', 'Update a project team member by ID. Requires project_team_members:write scope.', {
|
|
2177
|
+
id: z.string().uuid().describe('Project team member ID'),
|
|
2178
|
+
project_id: z.string().uuid().optional().describe('Project ID'),
|
|
2179
|
+
user_id: z.string().min(1).max(200).optional().describe('Clerk user ID'),
|
|
2180
|
+
role: z.string().min(1).max(100).optional().describe('Role on the project'),
|
|
2181
|
+
responsibilities: z.string().optional().describe('Description of responsibilities'),
|
|
2182
|
+
start_date: z.string().optional().describe('Start date (ISO 8601)'),
|
|
2183
|
+
end_date: z.string().optional().describe('End date (ISO 8601)'),
|
|
2184
|
+
is_active: z.boolean().optional().describe('Whether member is currently active'),
|
|
2185
|
+
}, async ({ id, ...rest }) => {
|
|
2186
|
+
try {
|
|
2187
|
+
const result = await client.update('project-team-members', id, buildBody(rest));
|
|
2188
|
+
return formatResult(result);
|
|
2189
|
+
}
|
|
2190
|
+
catch (err) {
|
|
2191
|
+
return formatError(err);
|
|
2192
|
+
}
|
|
2193
|
+
});
|
|
2194
|
+
server.tool('delete_project_team_member', 'Remove a team member from a project by ID. Requires project_team_members:write scope.', { id: z.string().uuid().describe('Project team member ID') }, async ({ id }) => {
|
|
2195
|
+
try {
|
|
2196
|
+
const result = await client.remove('project-team-members', id);
|
|
2197
|
+
return formatResult(result);
|
|
2198
|
+
}
|
|
2199
|
+
catch (err) {
|
|
2200
|
+
return formatError(err);
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
// ============================================================
|
|
2204
|
+
// Project Task Dependencies
|
|
2205
|
+
// ============================================================
|
|
2206
|
+
server.tool('create_project_task_dependency', 'Create a dependency between two project tasks. Requires project_task_dependencies:write scope.', {
|
|
2207
|
+
task_id: z.string().uuid().describe('Task ID (the dependent task, required)'),
|
|
2208
|
+
depends_on_task_id: z.string().uuid().describe('Task ID that must complete first (required)'),
|
|
2209
|
+
dependency_type: z.enum(['finish_to_start', 'start_to_start', 'finish_to_finish', 'start_to_finish']).optional().describe('Dependency type (default: finish_to_start)'),
|
|
2210
|
+
}, async (params) => {
|
|
2211
|
+
try {
|
|
2212
|
+
const result = await client.create('project-task-dependencies', buildBody(params));
|
|
2213
|
+
return formatResult(result);
|
|
2214
|
+
}
|
|
2215
|
+
catch (err) {
|
|
2216
|
+
return formatError(err);
|
|
2217
|
+
}
|
|
2218
|
+
});
|
|
2219
|
+
server.tool('delete_project_task_dependency', 'Delete a task dependency by ID. Requires project_task_dependencies:write scope.', { id: z.string().uuid().describe('Project task dependency ID') }, async ({ id }) => {
|
|
2220
|
+
try {
|
|
2221
|
+
const result = await client.remove('project-task-dependencies', id);
|
|
2222
|
+
return formatResult(result);
|
|
2223
|
+
}
|
|
2224
|
+
catch (err) {
|
|
2225
|
+
return formatError(err);
|
|
2226
|
+
}
|
|
2227
|
+
});
|
|
2228
|
+
// ============================================================
|
|
2229
|
+
// Project Updates
|
|
2230
|
+
// ============================================================
|
|
2231
|
+
server.tool('create_project_update', 'Create a periodic project status update. Requires project_updates:write scope.', {
|
|
2232
|
+
project_id: z.string().uuid().describe('Project ID (required)'),
|
|
2233
|
+
author_id: z.string().min(1).max(200).describe('Author Clerk user ID (required)'),
|
|
2234
|
+
timeframe: z.enum(['monthly', 'quarterly', 'bi-annually', 'annually']).describe('Update timeframe (required)'),
|
|
2235
|
+
period_year: z.number().int().min(2000).max(2100).describe('Year for this update period (required)'),
|
|
2236
|
+
period_value: z.string().min(1).max(20).describe('Period value — 1-12 for monthly, 1-4 for quarterly, etc. (required)'),
|
|
2237
|
+
content: z.string().min(1).describe('Update content (required)'),
|
|
2238
|
+
title: z.string().max(500).optional().describe('Optional custom title'),
|
|
2239
|
+
}, async (params) => {
|
|
2240
|
+
try {
|
|
2241
|
+
const result = await client.create('project-updates', buildBody(params));
|
|
2242
|
+
return formatResult(result);
|
|
2243
|
+
}
|
|
2244
|
+
catch (err) {
|
|
2245
|
+
return formatError(err);
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
server.tool('update_project_update', 'Update an existing project update by ID. Requires project_updates:write scope.', {
|
|
2249
|
+
id: z.string().uuid().describe('Project update ID'),
|
|
2250
|
+
project_id: z.string().uuid().optional().describe('Project ID'),
|
|
2251
|
+
author_id: z.string().min(1).max(200).optional().describe('Author Clerk user ID'),
|
|
2252
|
+
timeframe: z.enum(['monthly', 'quarterly', 'bi-annually', 'annually']).optional().describe('Update timeframe'),
|
|
2253
|
+
period_year: z.number().int().min(2000).max(2100).optional().describe('Year for this update period'),
|
|
2254
|
+
period_value: z.string().min(1).max(20).optional().describe('Period value'),
|
|
2255
|
+
content: z.string().min(1).optional().describe('Update content'),
|
|
2256
|
+
title: z.string().max(500).optional().describe('Optional custom title'),
|
|
2257
|
+
}, async ({ id, ...rest }) => {
|
|
2258
|
+
try {
|
|
2259
|
+
const result = await client.update('project-updates', id, buildBody(rest));
|
|
2260
|
+
return formatResult(result);
|
|
2261
|
+
}
|
|
2262
|
+
catch (err) {
|
|
2263
|
+
return formatError(err);
|
|
2264
|
+
}
|
|
2265
|
+
});
|
|
2266
|
+
server.tool('delete_project_update', 'Delete a project update by ID. Requires project_updates:write scope.', { id: z.string().uuid().describe('Project update ID') }, async ({ id }) => {
|
|
2267
|
+
try {
|
|
2268
|
+
const result = await client.remove('project-updates', id);
|
|
2269
|
+
return formatResult(result);
|
|
2270
|
+
}
|
|
2271
|
+
catch (err) {
|
|
2272
|
+
return formatError(err);
|
|
2273
|
+
}
|
|
2274
|
+
});
|
|
2275
|
+
// ============================================================
|
|
2276
|
+
// Project Cost Snapshots
|
|
2277
|
+
// ============================================================
|
|
2278
|
+
server.tool('create_project_cost_snapshot', 'Record a cost snapshot for a project at a point in time. Requires project_cost_snapshots:write scope.', {
|
|
2279
|
+
project_id: z.string().uuid().describe('Project ID (required)'),
|
|
2280
|
+
snapshot_date: z.string().describe('Snapshot date (ISO 8601, required)'),
|
|
2281
|
+
total_budget: z.number().min(0).describe('Total budget amount (required)'),
|
|
2282
|
+
actual_cost: z.number().min(0).describe('Actual cost to date (required)'),
|
|
2283
|
+
forecasted_cost: z.number().min(0).optional().describe('Forecasted total cost'),
|
|
2284
|
+
percent_complete: z.number().min(0).max(100).optional().describe('Completion percentage (0-100)'),
|
|
2285
|
+
}, async (params) => {
|
|
2286
|
+
try {
|
|
2287
|
+
const result = await client.create('project-cost-snapshots', buildBody(params));
|
|
2288
|
+
return formatResult(result);
|
|
2289
|
+
}
|
|
2290
|
+
catch (err) {
|
|
2291
|
+
return formatError(err);
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
server.tool('delete_project_cost_snapshot', 'Delete a project cost snapshot by ID. Requires project_cost_snapshots:write scope.', { id: z.string().uuid().describe('Project cost snapshot ID') }, async ({ id }) => {
|
|
2295
|
+
try {
|
|
2296
|
+
const result = await client.remove('project-cost-snapshots', id);
|
|
2297
|
+
return formatResult(result);
|
|
2298
|
+
}
|
|
2299
|
+
catch (err) {
|
|
2300
|
+
return formatError(err);
|
|
2301
|
+
}
|
|
2302
|
+
});
|
|
2303
|
+
// ============================================================
|
|
2304
|
+
// Project Locations
|
|
2305
|
+
// ============================================================
|
|
2306
|
+
server.tool('create_project_location', 'Link a location to a project. Requires project_locations:write scope.', {
|
|
2307
|
+
project_id: z.string().uuid().describe('Project ID (required)'),
|
|
2308
|
+
location_id: z.string().uuid().describe('Location ID (required)'),
|
|
2309
|
+
}, async (params) => {
|
|
2310
|
+
try {
|
|
2311
|
+
const result = await client.create('project-locations', buildBody(params));
|
|
2312
|
+
return formatResult(result);
|
|
2313
|
+
}
|
|
2314
|
+
catch (err) {
|
|
2315
|
+
return formatError(err);
|
|
2316
|
+
}
|
|
2317
|
+
});
|
|
2318
|
+
server.tool('delete_project_location', 'Remove a location from a project by ID. Requires project_locations:write scope.', { id: z.string().uuid().describe('Project location ID') }, async ({ id }) => {
|
|
2319
|
+
try {
|
|
2320
|
+
const result = await client.remove('project-locations', id);
|
|
2321
|
+
return formatResult(result);
|
|
2322
|
+
}
|
|
2323
|
+
catch (err) {
|
|
2324
|
+
return formatError(err);
|
|
2325
|
+
}
|
|
2326
|
+
});
|
|
2327
|
+
// ============================================================
|
|
1938
2328
|
// Bulk operations
|
|
1939
2329
|
// ============================================================
|
|
1940
2330
|
const BULK_RESOURCES = [
|
|
@@ -1946,9 +2336,12 @@ export function registerWriteTools(server, client) {
|
|
|
1946
2336
|
'asset-comments', 'asset-costs', 'asset-replacement-plans',
|
|
1947
2337
|
'work-order-comments', 'project-tasks', 'project-milestones',
|
|
1948
2338
|
'project-phases', 'project-budget-items', 'project-time-entries',
|
|
1949
|
-
'project-comments', '
|
|
2339
|
+
'project-comments', 'project-team-members', 'project-task-dependencies',
|
|
2340
|
+
'project-updates', 'project-cost-snapshots', 'project-locations',
|
|
2341
|
+
'parts', 'part-categories',
|
|
1950
2342
|
'custom-field-definitions', 'custom-field-values',
|
|
1951
2343
|
'vendor-site-assignments', 'contract-sites',
|
|
2344
|
+
'asset-documents', 'attachments', 'project-documents', 'contract-documents',
|
|
1952
2345
|
];
|
|
1953
2346
|
server.tool('bulk_create', 'Create multiple records of a resource type in one API call (max 100). Each item is processed independently — one failure does not affect others. Returns per-item results. Requires {resource}:write scope. Counts as 1 request for rate limiting.', {
|
|
1954
2347
|
resource: z.enum(BULK_RESOURCES).describe('Resource type (e.g. "assets", "work-orders")'),
|
|
@@ -1962,6 +2355,135 @@ export function registerWriteTools(server, client) {
|
|
|
1962
2355
|
return formatError(err);
|
|
1963
2356
|
}
|
|
1964
2357
|
});
|
|
2358
|
+
// ============================================================
|
|
2359
|
+
// Asset Statuses (scope: asset_statuses)
|
|
2360
|
+
// ============================================================
|
|
2361
|
+
server.tool('create_asset_status', 'Create a new asset status (lifecycle state for assets). Requires asset_statuses:write scope.', {
|
|
2362
|
+
name: z.string().max(500).describe('Status name (required)'),
|
|
2363
|
+
description: z.string().optional().describe('Description'),
|
|
2364
|
+
}, async (params) => {
|
|
2365
|
+
try {
|
|
2366
|
+
const result = await client.create('asset-statuses', buildBody(params));
|
|
2367
|
+
return formatResult(result);
|
|
2368
|
+
}
|
|
2369
|
+
catch (err) {
|
|
2370
|
+
return formatError(err);
|
|
2371
|
+
}
|
|
2372
|
+
});
|
|
2373
|
+
server.tool('update_asset_status', 'Update an existing asset status by ID. Requires asset_statuses:write scope.', {
|
|
2374
|
+
id: z.string().uuid().describe('Asset status ID'),
|
|
2375
|
+
name: z.string().max(500).optional().describe('Status name'),
|
|
2376
|
+
description: z.string().optional().describe('Description'),
|
|
2377
|
+
}, async ({ id, ...rest }) => {
|
|
2378
|
+
try {
|
|
2379
|
+
const result = await client.update('asset-statuses', id, buildBody(rest));
|
|
2380
|
+
return formatResult(result);
|
|
2381
|
+
}
|
|
2382
|
+
catch (err) {
|
|
2383
|
+
return formatError(err);
|
|
2384
|
+
}
|
|
2385
|
+
});
|
|
2386
|
+
server.tool('delete_asset_status', 'Delete an asset status by ID. Requires asset_statuses:write scope.', { id: z.string().uuid().describe('Asset status ID') }, async ({ id }) => {
|
|
2387
|
+
try {
|
|
2388
|
+
const result = await client.remove('asset-statuses', id);
|
|
2389
|
+
return formatResult(result);
|
|
2390
|
+
}
|
|
2391
|
+
catch (err) {
|
|
2392
|
+
return formatError(err);
|
|
2393
|
+
}
|
|
2394
|
+
});
|
|
2395
|
+
// ============================================================
|
|
2396
|
+
// Compliance Items (scope: compliance)
|
|
2397
|
+
// ============================================================
|
|
2398
|
+
server.tool('create_compliance_item', 'Create a new compliance item (regulatory requirement). Requires compliance:write scope.', {
|
|
2399
|
+
name: z.string().max(500).describe('Compliance item name (required)'),
|
|
2400
|
+
description: z.string().optional().describe('Description'),
|
|
2401
|
+
regulation_reference: z.string().max(500).optional().describe('Regulation or code reference'),
|
|
2402
|
+
compliance_period_months: z.number().int().min(1).optional().describe('Compliance period in months'),
|
|
2403
|
+
status: z.enum(['active', 'archived']).optional().describe('Status'),
|
|
2404
|
+
system_id: z.string().uuid().optional().describe('Associated system ID'),
|
|
2405
|
+
}, async (params) => {
|
|
2406
|
+
try {
|
|
2407
|
+
const result = await client.create('compliance', buildBody(params));
|
|
2408
|
+
return formatResult(result);
|
|
2409
|
+
}
|
|
2410
|
+
catch (err) {
|
|
2411
|
+
return formatError(err);
|
|
2412
|
+
}
|
|
2413
|
+
});
|
|
2414
|
+
server.tool('update_compliance_item', 'Update an existing compliance item by ID. Requires compliance:write scope.', {
|
|
2415
|
+
id: z.string().uuid().describe('Compliance item ID'),
|
|
2416
|
+
name: z.string().max(500).optional().describe('Compliance item name'),
|
|
2417
|
+
description: z.string().optional().describe('Description'),
|
|
2418
|
+
regulation_reference: z.string().max(500).optional().describe('Regulation or code reference'),
|
|
2419
|
+
compliance_period_months: z.number().int().min(1).optional().describe('Compliance period in months'),
|
|
2420
|
+
status: z.enum(['active', 'archived']).optional().describe('Status'),
|
|
2421
|
+
system_id: z.string().uuid().optional().describe('Associated system ID'),
|
|
2422
|
+
}, async ({ id, ...rest }) => {
|
|
2423
|
+
try {
|
|
2424
|
+
const result = await client.update('compliance', id, buildBody(rest));
|
|
2425
|
+
return formatResult(result);
|
|
2426
|
+
}
|
|
2427
|
+
catch (err) {
|
|
2428
|
+
return formatError(err);
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2431
|
+
server.tool('delete_compliance_item', 'Delete a compliance item by ID. Requires compliance:write scope.', { id: z.string().uuid().describe('Compliance item ID') }, async ({ id }) => {
|
|
2432
|
+
try {
|
|
2433
|
+
const result = await client.remove('compliance', id);
|
|
2434
|
+
return formatResult(result);
|
|
2435
|
+
}
|
|
2436
|
+
catch (err) {
|
|
2437
|
+
return formatError(err);
|
|
2438
|
+
}
|
|
2439
|
+
});
|
|
2440
|
+
// ============================================================
|
|
2441
|
+
// Compliance Records (scope: compliance_records)
|
|
2442
|
+
// ============================================================
|
|
2443
|
+
server.tool('create_compliance_record', 'Create a new compliance record (audit trail entry). Requires compliance_records:write scope.', {
|
|
2444
|
+
compliance_item_id: z.string().uuid().describe('Compliance item ID (required)'),
|
|
2445
|
+
pm_schedule_id: z.string().uuid().describe('PM schedule ID (required)'),
|
|
2446
|
+
work_order_id: z.string().uuid().describe('Work order ID (required)'),
|
|
2447
|
+
completed_at: z.string().describe('Completion date-time (ISO 8601, required)'),
|
|
2448
|
+
completed_by: z.string().max(200).optional().describe('User ID who completed'),
|
|
2449
|
+
required_frequency_days: z.number().int().min(1).describe('Required frequency in days (required)'),
|
|
2450
|
+
days_since_last_completion: z.number().int().min(0).optional().describe('Days since last completion'),
|
|
2451
|
+
}, async (params) => {
|
|
2452
|
+
try {
|
|
2453
|
+
const result = await client.create('compliance-records', buildBody(params));
|
|
2454
|
+
return formatResult(result);
|
|
2455
|
+
}
|
|
2456
|
+
catch (err) {
|
|
2457
|
+
return formatError(err);
|
|
2458
|
+
}
|
|
2459
|
+
});
|
|
2460
|
+
server.tool('update_compliance_record', 'Update an existing compliance record by ID. Requires compliance_records:write scope.', {
|
|
2461
|
+
id: z.string().uuid().describe('Compliance record ID'),
|
|
2462
|
+
completed_at: z.string().optional().describe('Completion date-time (ISO 8601)'),
|
|
2463
|
+
completed_by: z.string().max(200).optional().describe('User ID who completed'),
|
|
2464
|
+
required_frequency_days: z.number().int().min(1).optional().describe('Required frequency in days'),
|
|
2465
|
+
days_since_last_completion: z.number().int().min(0).optional().describe('Days since last completion'),
|
|
2466
|
+
}, async ({ id, ...rest }) => {
|
|
2467
|
+
try {
|
|
2468
|
+
const result = await client.update('compliance-records', id, buildBody(rest));
|
|
2469
|
+
return formatResult(result);
|
|
2470
|
+
}
|
|
2471
|
+
catch (err) {
|
|
2472
|
+
return formatError(err);
|
|
2473
|
+
}
|
|
2474
|
+
});
|
|
2475
|
+
server.tool('delete_compliance_record', 'Delete a compliance record by ID. Requires compliance_records:write scope.', { id: z.string().uuid().describe('Compliance record ID') }, async ({ id }) => {
|
|
2476
|
+
try {
|
|
2477
|
+
const result = await client.remove('compliance-records', id);
|
|
2478
|
+
return formatResult(result);
|
|
2479
|
+
}
|
|
2480
|
+
catch (err) {
|
|
2481
|
+
return formatError(err);
|
|
2482
|
+
}
|
|
2483
|
+
});
|
|
2484
|
+
// ============================================================
|
|
2485
|
+
// Bulk Operations
|
|
2486
|
+
// ============================================================
|
|
1965
2487
|
server.tool('bulk_update', 'Update multiple records of a resource type in one API call (max 100). Each item must include an "id" field (UUID). Each item is processed independently — one failure does not affect others. Returns per-item results. Requires {resource}:write scope. Counts as 1 request for rate limiting.', {
|
|
1966
2488
|
resource: z.enum(BULK_RESOURCES).describe('Resource type (e.g. "assets", "work-orders")'),
|
|
1967
2489
|
items: z.array(z.record(z.unknown())).min(1).max(100).describe('Array of objects to update (max 100). Each must include an "id" field (UUID) plus fields to change.'),
|