snow-flow 3.4.13 → 3.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +23 -51
- package/dist/mcp/servicenow-automation-mcp.js +65 -29
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp.js +51 -21
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp.js +59 -25
- package/dist/mcp/servicenow-deployment-mcp.js +38 -16
- package/dist/mcp/servicenow-development-assistant-mcp.js +67 -31
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp.js +53 -22
- package/dist/mcp/servicenow-integration-mcp.js +48 -12
- package/dist/mcp/servicenow-knowledge-catalog-mcp.js +42 -16
- package/dist/mcp/servicenow-machine-learning-mcp.js +44 -17
- package/dist/mcp/servicenow-operations-mcp.d.ts +1 -0
- package/dist/mcp/servicenow-operations-mcp.js +108 -79
- package/dist/mcp/servicenow-platform-development-mcp.js +42 -11
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +36 -13
- package/dist/mcp/servicenow-security-compliance-mcp.js +35 -13
- package/dist/mcp/servicenow-system-properties-mcp.d.ts +1 -0
- package/dist/mcp/servicenow-system-properties-mcp.js +66 -42
- package/dist/mcp/servicenow-update-set-mcp.js +35 -11
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
|
12
12
|
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
13
13
|
const mcp_auth_middleware_js_1 = require("../utils/mcp-auth-middleware.js");
|
|
14
14
|
const mcp_config_manager_js_1 = require("../utils/mcp-config-manager.js");
|
|
15
|
-
const
|
|
15
|
+
const mcp_logger_js_1 = require("../shared/mcp-logger.js");
|
|
16
16
|
class ServiceNowIntegrationMCP {
|
|
17
17
|
constructor() {
|
|
18
18
|
this.server = new index_js_1.Server({
|
|
@@ -24,7 +24,7 @@ class ServiceNowIntegrationMCP {
|
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
27
|
-
this.logger = new
|
|
27
|
+
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowIntegrationMCP');
|
|
28
28
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
29
29
|
this.setupHandlers();
|
|
30
30
|
}
|
|
@@ -177,34 +177,50 @@ class ServiceNowIntegrationMCP {
|
|
|
177
177
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
178
178
|
try {
|
|
179
179
|
const { name, arguments: args } = request.params;
|
|
180
|
+
// Start operation with token tracking
|
|
181
|
+
this.logger.operationStart(name, args);
|
|
180
182
|
const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
181
183
|
if (!authResult.success) {
|
|
182
184
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required');
|
|
183
185
|
}
|
|
186
|
+
let result;
|
|
184
187
|
switch (name) {
|
|
185
188
|
case 'snow_create_rest_message':
|
|
186
|
-
|
|
189
|
+
result = await this.createRestMessage(args);
|
|
190
|
+
break;
|
|
187
191
|
case 'snow_create_rest_method':
|
|
188
|
-
|
|
192
|
+
result = await this.createRestMethod(args);
|
|
193
|
+
break;
|
|
189
194
|
case 'snow_create_transform_map':
|
|
190
|
-
|
|
195
|
+
result = await this.createTransformMap(args);
|
|
196
|
+
break;
|
|
191
197
|
case 'snow_create_field_map':
|
|
192
|
-
|
|
198
|
+
result = await this.createFieldMap(args);
|
|
199
|
+
break;
|
|
193
200
|
case 'snow_create_import_set':
|
|
194
|
-
|
|
201
|
+
result = await this.createImportSet(args);
|
|
202
|
+
break;
|
|
195
203
|
case 'snow_create_web_service':
|
|
196
|
-
|
|
204
|
+
result = await this.createWebService(args);
|
|
205
|
+
break;
|
|
197
206
|
case 'snow_create_email_config':
|
|
198
|
-
|
|
207
|
+
result = await this.createEmailConfig(args);
|
|
208
|
+
break;
|
|
199
209
|
case 'snow_discover_integration_endpoints':
|
|
200
|
-
|
|
210
|
+
result = await this.discoverIntegrationEndpoints(args);
|
|
211
|
+
break;
|
|
201
212
|
case 'snow_test_integration':
|
|
202
|
-
|
|
213
|
+
result = await this.testIntegration(args);
|
|
214
|
+
break;
|
|
203
215
|
case 'snow_discover_data_sources':
|
|
204
|
-
|
|
216
|
+
result = await this.discoverDataSources(args);
|
|
217
|
+
break;
|
|
205
218
|
default:
|
|
206
219
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
207
220
|
}
|
|
221
|
+
// Complete operation with token tracking
|
|
222
|
+
this.logger.operationComplete(name, result);
|
|
223
|
+
return result;
|
|
208
224
|
}
|
|
209
225
|
catch (error) {
|
|
210
226
|
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
@@ -228,6 +244,7 @@ class ServiceNowIntegrationMCP {
|
|
|
228
244
|
authentication_profile: args.authProfile || ''
|
|
229
245
|
};
|
|
230
246
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
247
|
+
this.logger.trackAPICall('CREATE', 'sys_rest_message', 1);
|
|
231
248
|
const response = await this.client.createRecord('sys_rest_message', restMessageData);
|
|
232
249
|
if (!response.success) {
|
|
233
250
|
throw new Error(`Failed to create REST Message: ${response.error}`);
|
|
@@ -263,6 +280,7 @@ class ServiceNowIntegrationMCP {
|
|
|
263
280
|
content: args.content || '',
|
|
264
281
|
headers: JSON.stringify(args.headers || {})
|
|
265
282
|
};
|
|
283
|
+
this.logger.trackAPICall('CREATE', 'sys_rest_message_fn', 1);
|
|
266
284
|
const response = await this.client.createRecord('sys_rest_message_fn', restMethodData);
|
|
267
285
|
if (!response.success) {
|
|
268
286
|
throw new Error(`Failed to create REST Method: ${response.error}`);
|
|
@@ -303,6 +321,7 @@ class ServiceNowIntegrationMCP {
|
|
|
303
321
|
active: args.active !== false
|
|
304
322
|
};
|
|
305
323
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
324
|
+
this.logger.trackAPICall('CREATE', 'sys_transform_map', 1);
|
|
306
325
|
const response = await this.client.createRecord('sys_transform_map', transformMapData);
|
|
307
326
|
if (!response.success) {
|
|
308
327
|
throw new Error(`Failed to create Transform Map: ${response.error}`);
|
|
@@ -341,6 +360,7 @@ class ServiceNowIntegrationMCP {
|
|
|
341
360
|
default_value: args.defaultValue || '',
|
|
342
361
|
map: transformMap.sys_id
|
|
343
362
|
};
|
|
363
|
+
this.logger.trackAPICall('CREATE', 'sys_transform_entry', 1);
|
|
344
364
|
const response = await this.client.createRecord('sys_transform_entry', fieldMapData);
|
|
345
365
|
if (!response.success) {
|
|
346
366
|
throw new Error(`Failed to create Field Map: ${response.error}`);
|
|
@@ -379,6 +399,7 @@ class ServiceNowIntegrationMCP {
|
|
|
379
399
|
};
|
|
380
400
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
381
401
|
// Create the import set table structure first
|
|
402
|
+
this.logger.trackAPICall('CREATE', 'sys_db_object', 1);
|
|
382
403
|
const response = await this.client.createRecord('sys_db_object', importSetData);
|
|
383
404
|
if (!response.success) {
|
|
384
405
|
this.logger.error('Import Set creation failed with response:', response);
|
|
@@ -393,6 +414,7 @@ class ServiceNowIntegrationMCP {
|
|
|
393
414
|
description: 'Row number from import file'
|
|
394
415
|
};
|
|
395
416
|
try {
|
|
417
|
+
this.logger.trackAPICall('CREATE', 'sys_dictionary', 1);
|
|
396
418
|
await this.client.createRecord('sys_dictionary', fieldData);
|
|
397
419
|
}
|
|
398
420
|
catch (fieldError) {
|
|
@@ -426,6 +448,7 @@ class ServiceNowIntegrationMCP {
|
|
|
426
448
|
namespace: args.namespace || ''
|
|
427
449
|
};
|
|
428
450
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
451
|
+
this.logger.trackAPICall('CREATE', 'sys_web_service', 1);
|
|
429
452
|
const response = await this.client.createRecord('sys_web_service', webServiceData);
|
|
430
453
|
if (!response.success) {
|
|
431
454
|
throw new Error(`Failed to create Web Service: ${response.error}`);
|
|
@@ -458,6 +481,7 @@ class ServiceNowIntegrationMCP {
|
|
|
458
481
|
description: args.description || ''
|
|
459
482
|
};
|
|
460
483
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
484
|
+
this.logger.trackAPICall('CREATE', 'sys_email_account', 1);
|
|
461
485
|
const response = await this.client.createRecord('sys_email_account', emailConfigData);
|
|
462
486
|
if (!response.success) {
|
|
463
487
|
throw new Error(`Failed to create Email Configuration: ${response.error}`);
|
|
@@ -484,6 +508,7 @@ class ServiceNowIntegrationMCP {
|
|
|
484
508
|
const endpoints = [];
|
|
485
509
|
// Discover REST Messages
|
|
486
510
|
if (type === 'all' || type === 'REST') {
|
|
511
|
+
this.logger.trackAPICall('SEARCH', 'sys_rest_message', 50);
|
|
487
512
|
const restMessages = await this.client.searchRecords('sys_rest_message', '', 50);
|
|
488
513
|
if (restMessages.success) {
|
|
489
514
|
endpoints.push({
|
|
@@ -499,6 +524,7 @@ class ServiceNowIntegrationMCP {
|
|
|
499
524
|
}
|
|
500
525
|
// Discover Web Services
|
|
501
526
|
if (type === 'all' || type === 'SOAP') {
|
|
527
|
+
this.logger.trackAPICall('SEARCH', 'sys_web_service', 50);
|
|
502
528
|
const webServices = await this.client.searchRecords('sys_web_service', '', 50);
|
|
503
529
|
if (webServices.success) {
|
|
504
530
|
endpoints.push({
|
|
@@ -514,6 +540,7 @@ class ServiceNowIntegrationMCP {
|
|
|
514
540
|
}
|
|
515
541
|
// Discover Email Accounts
|
|
516
542
|
if (type === 'all' || type === 'EMAIL') {
|
|
543
|
+
this.logger.trackAPICall('SEARCH', 'sys_email_account', 50);
|
|
517
544
|
const emailAccounts = await this.client.searchRecords('sys_email_account', '', 50);
|
|
518
545
|
if (emailAccounts.success) {
|
|
519
546
|
endpoints.push({
|
|
@@ -552,6 +579,7 @@ class ServiceNowIntegrationMCP {
|
|
|
552
579
|
throw new Error(`Integration endpoint not found: ${args.endpointName}`);
|
|
553
580
|
}
|
|
554
581
|
// Get available test methods
|
|
582
|
+
this.logger.trackAPICall('SEARCH', 'sys_rest_message_fn', 10);
|
|
555
583
|
const methods = await this.client.searchRecords('sys_rest_message_fn', `rest_message=${restMessage.sys_id}`, 10);
|
|
556
584
|
if (!methods.success || !methods.data.result.length) {
|
|
557
585
|
throw new Error(`No methods found for REST Message: ${args.endpointName}`);
|
|
@@ -576,6 +604,7 @@ class ServiceNowIntegrationMCP {
|
|
|
576
604
|
this.logger.info('Discovering data sources...');
|
|
577
605
|
const dataSources = [];
|
|
578
606
|
// Discover Import Sets
|
|
607
|
+
this.logger.trackAPICall('SEARCH', 'sys_import_set_table', 50);
|
|
579
608
|
const importSets = await this.client.searchRecords('sys_import_set_table', '', 50);
|
|
580
609
|
if (importSets.success) {
|
|
581
610
|
dataSources.push({
|
|
@@ -589,6 +618,7 @@ class ServiceNowIntegrationMCP {
|
|
|
589
618
|
});
|
|
590
619
|
}
|
|
591
620
|
// Discover Transform Maps
|
|
621
|
+
this.logger.trackAPICall('SEARCH', 'sys_transform_map', 50);
|
|
592
622
|
const transformMaps = await this.client.searchRecords('sys_transform_map', '', 50);
|
|
593
623
|
if (transformMaps.success) {
|
|
594
624
|
dataSources.push({
|
|
@@ -602,6 +632,7 @@ class ServiceNowIntegrationMCP {
|
|
|
602
632
|
});
|
|
603
633
|
}
|
|
604
634
|
// Discover Data Sources
|
|
635
|
+
this.logger.trackAPICall('SEARCH', 'sys_data_source', 50);
|
|
605
636
|
const dataSourcesResponse = await this.client.searchRecords('sys_data_source', '', 50);
|
|
606
637
|
if (dataSourcesResponse.success) {
|
|
607
638
|
dataSources.push({
|
|
@@ -630,6 +661,7 @@ class ServiceNowIntegrationMCP {
|
|
|
630
661
|
async getAuthenticationTypes() {
|
|
631
662
|
// Discover available authentication types dynamically
|
|
632
663
|
try {
|
|
664
|
+
this.logger.trackAPICall('SEARCH', 'sys_choice', 10);
|
|
633
665
|
const authTypes = await this.client.searchRecords('sys_choice', 'name=sys_rest_message^element=authentication_type', 10);
|
|
634
666
|
if (authTypes.success) {
|
|
635
667
|
return authTypes.data.result.map((choice) => choice.value);
|
|
@@ -642,6 +674,7 @@ class ServiceNowIntegrationMCP {
|
|
|
642
674
|
}
|
|
643
675
|
async getTableInfo(tableName) {
|
|
644
676
|
try {
|
|
677
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 1);
|
|
645
678
|
const tableResponse = await this.client.searchRecords('sys_db_object', `name=${tableName}`, 1);
|
|
646
679
|
if (tableResponse.success && tableResponse.data?.result?.length > 0) {
|
|
647
680
|
const table = tableResponse.data.result[0];
|
|
@@ -656,6 +689,7 @@ class ServiceNowIntegrationMCP {
|
|
|
656
689
|
}
|
|
657
690
|
async getTableFields(tableName) {
|
|
658
691
|
try {
|
|
692
|
+
this.logger.trackAPICall('SEARCH', 'sys_dictionary', 100);
|
|
659
693
|
const fieldsResponse = await this.client.searchRecords('sys_dictionary', `nameSTARTSWITH${tableName}^element!=NULL`, 100);
|
|
660
694
|
if (fieldsResponse.success) {
|
|
661
695
|
return fieldsResponse.data.result.map((field) => field.element);
|
|
@@ -669,6 +703,7 @@ class ServiceNowIntegrationMCP {
|
|
|
669
703
|
}
|
|
670
704
|
async findRestMessage(name) {
|
|
671
705
|
try {
|
|
706
|
+
this.logger.trackAPICall('SEARCH', 'sys_rest_message', 1);
|
|
672
707
|
const response = await this.client.searchRecords('sys_rest_message', `name=${name}`, 1);
|
|
673
708
|
if (response.success && response.data?.result?.length > 0) {
|
|
674
709
|
return response.data.result[0];
|
|
@@ -682,6 +717,7 @@ class ServiceNowIntegrationMCP {
|
|
|
682
717
|
}
|
|
683
718
|
async findTransformMap(name) {
|
|
684
719
|
try {
|
|
720
|
+
this.logger.trackAPICall('SEARCH', 'sys_transform_map', 1);
|
|
685
721
|
const response = await this.client.searchRecords('sys_transform_map', `name=${name}`, 1);
|
|
686
722
|
if (response.success && response.data?.result?.length > 0) {
|
|
687
723
|
return response.data.result[0];
|
|
@@ -12,7 +12,7 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
|
12
12
|
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
13
13
|
const mcp_auth_middleware_js_1 = require("../utils/mcp-auth-middleware.js");
|
|
14
14
|
const mcp_config_manager_js_1 = require("../utils/mcp-config-manager.js");
|
|
15
|
-
const
|
|
15
|
+
const mcp_logger_js_1 = require("../shared/mcp-logger.js");
|
|
16
16
|
class ServiceNowKnowledgeCatalogMCP {
|
|
17
17
|
constructor() {
|
|
18
18
|
this.server = new index_js_1.Server({
|
|
@@ -24,7 +24,7 @@ class ServiceNowKnowledgeCatalogMCP {
|
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
27
|
-
this.logger = new
|
|
27
|
+
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowKnowledgeCatalogMCP');
|
|
28
28
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
29
29
|
this.setupHandlers();
|
|
30
30
|
}
|
|
@@ -263,44 +263,64 @@ class ServiceNowKnowledgeCatalogMCP {
|
|
|
263
263
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
264
264
|
try {
|
|
265
265
|
const { name, arguments: args } = request.params;
|
|
266
|
+
// Start operation with token tracking
|
|
267
|
+
this.logger.operationStart(name, args);
|
|
266
268
|
const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
267
269
|
if (!authResult.success) {
|
|
268
270
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required');
|
|
269
271
|
}
|
|
272
|
+
let result;
|
|
270
273
|
switch (name) {
|
|
271
274
|
// Knowledge Management
|
|
272
275
|
case 'snow_create_knowledge_article':
|
|
273
|
-
|
|
276
|
+
result = await this.createKnowledgeArticle(args);
|
|
277
|
+
break;
|
|
274
278
|
case 'snow_search_knowledge':
|
|
275
|
-
|
|
279
|
+
result = await this.searchKnowledge(args);
|
|
280
|
+
break;
|
|
276
281
|
case 'snow_update_knowledge_article':
|
|
277
|
-
|
|
282
|
+
result = await this.updateKnowledgeArticle(args);
|
|
283
|
+
break;
|
|
278
284
|
case 'snow_retire_knowledge_article':
|
|
279
|
-
|
|
285
|
+
result = await this.retireKnowledgeArticle(args);
|
|
286
|
+
break;
|
|
280
287
|
case 'snow_create_knowledge_base':
|
|
281
|
-
|
|
288
|
+
result = await this.createKnowledgeBase(args);
|
|
289
|
+
break;
|
|
282
290
|
case 'snow_discover_knowledge_bases':
|
|
283
|
-
|
|
291
|
+
result = await this.discoverKnowledgeBases(args);
|
|
292
|
+
break;
|
|
284
293
|
// Service Catalog
|
|
285
294
|
case 'snow_create_catalog_item':
|
|
286
|
-
|
|
295
|
+
result = await this.createCatalogItem(args);
|
|
296
|
+
break;
|
|
287
297
|
case 'snow_create_catalog_variable':
|
|
288
|
-
|
|
298
|
+
result = await this.createCatalogVariable(args);
|
|
299
|
+
break;
|
|
289
300
|
case 'snow_create_catalog_ui_policy':
|
|
290
|
-
|
|
301
|
+
result = await this.createCatalogUIPolicy(args);
|
|
302
|
+
break;
|
|
291
303
|
case 'snow_create_catalog_client_script':
|
|
292
|
-
|
|
304
|
+
result = await this.createCatalogClientScript(args);
|
|
305
|
+
break;
|
|
293
306
|
case 'snow_search_catalog':
|
|
294
|
-
|
|
307
|
+
result = await this.searchCatalog(args);
|
|
308
|
+
break;
|
|
295
309
|
case 'snow_order_catalog_item':
|
|
296
|
-
|
|
310
|
+
result = await this.orderCatalogItem(args);
|
|
311
|
+
break;
|
|
297
312
|
case 'snow_get_catalog_item_details':
|
|
298
|
-
|
|
313
|
+
result = await this.getCatalogItemDetails(args);
|
|
314
|
+
break;
|
|
299
315
|
case 'snow_discover_catalogs':
|
|
300
|
-
|
|
316
|
+
result = await this.discoverCatalogs(args);
|
|
317
|
+
break;
|
|
301
318
|
default:
|
|
302
319
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
303
320
|
}
|
|
321
|
+
// Complete operation with token tracking
|
|
322
|
+
this.logger.operationComplete(name, result);
|
|
323
|
+
return result;
|
|
304
324
|
}
|
|
305
325
|
catch (error) {
|
|
306
326
|
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
@@ -344,6 +364,7 @@ class ServiceNowKnowledgeCatalogMCP {
|
|
|
344
364
|
author: args.author || ''
|
|
345
365
|
};
|
|
346
366
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
367
|
+
this.logger.trackAPICall('CREATE', 'kb_knowledge', 1);
|
|
347
368
|
const response = await this.client.createRecord('kb_knowledge', articleData);
|
|
348
369
|
if (!response.success) {
|
|
349
370
|
throw new Error(`Failed to create knowledge article: ${response.error}`);
|
|
@@ -392,6 +413,7 @@ ${args.valid_to ? `📅 Valid Until: ${args.valid_to}` : ''}
|
|
|
392
413
|
query += '^workflow_state=published'; // Default to published only
|
|
393
414
|
}
|
|
394
415
|
const limit = args.limit || 10;
|
|
416
|
+
this.logger.trackAPICall('SEARCH', 'kb_knowledge', limit);
|
|
395
417
|
const response = await this.client.searchRecords('kb_knowledge', query, limit);
|
|
396
418
|
if (!response.success) {
|
|
397
419
|
throw new Error('Failed to search knowledge articles');
|
|
@@ -450,6 +472,7 @@ ${articleList}
|
|
|
450
472
|
updateData.meta_description = args.meta_description;
|
|
451
473
|
if (args.keywords)
|
|
452
474
|
updateData.keywords = args.keywords.join(',');
|
|
475
|
+
this.logger.trackAPICall('UPDATE', 'kb_knowledge', 1);
|
|
453
476
|
const response = await this.client.updateRecord('kb_knowledge', args.sys_id, updateData);
|
|
454
477
|
if (!response.success) {
|
|
455
478
|
throw new Error(`Failed to update knowledge article: ${response.error}`);
|
|
@@ -487,6 +510,7 @@ ${args.valid_to ? `📅 Valid Until: ${args.valid_to}` : ''}
|
|
|
487
510
|
if (args.replacement_article) {
|
|
488
511
|
updateData['replacement_article'] = args.replacement_article;
|
|
489
512
|
}
|
|
513
|
+
this.logger.trackAPICall('UPDATE', 'kb_knowledge', 1);
|
|
490
514
|
const response = await this.client.updateRecord('kb_knowledge', args.sys_id, updateData);
|
|
491
515
|
if (!response.success) {
|
|
492
516
|
throw new Error(`Failed to retire knowledge article: ${response.error}`);
|
|
@@ -633,6 +657,7 @@ ${kbText}
|
|
|
633
657
|
mobile_hide_price: args.mobile_hide_price || false
|
|
634
658
|
};
|
|
635
659
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
660
|
+
this.logger.trackAPICall('CREATE', 'sc_cat_item', 1);
|
|
636
661
|
const response = await this.client.createRecord('sc_cat_item', itemData);
|
|
637
662
|
if (!response.success) {
|
|
638
663
|
throw new Error(`Failed to create catalog item: ${response.error}`);
|
|
@@ -808,6 +833,7 @@ ${args.variable ? `📝 Variable: ${args.variable}` : ''}
|
|
|
808
833
|
query += 'active=true';
|
|
809
834
|
}
|
|
810
835
|
const limit = args.limit || 20;
|
|
836
|
+
this.logger.trackAPICall('SEARCH', 'sc_cat_item', limit);
|
|
811
837
|
const response = await this.client.searchRecords('sc_cat_item', query, limit);
|
|
812
838
|
if (!response.success) {
|
|
813
839
|
throw new Error('Failed to search catalog');
|
|
@@ -73,7 +73,7 @@ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
73
73
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
74
74
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
75
75
|
const tf = __importStar(require("@tensorflow/tfjs-node"));
|
|
76
|
-
const
|
|
76
|
+
const mcp_logger_js_1 = require("./shared/mcp-logger.js");
|
|
77
77
|
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
78
78
|
const ml_data_fetcher_js_1 = require("../utils/ml-data-fetcher.js");
|
|
79
79
|
class ServiceNowMachineLearningMCP {
|
|
@@ -85,7 +85,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
85
85
|
this.hasPA = false;
|
|
86
86
|
this.hasPI = false;
|
|
87
87
|
this.mlAPICheckComplete = false;
|
|
88
|
-
this.logger = new
|
|
88
|
+
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowMachineLearning');
|
|
89
89
|
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
90
90
|
this.server = new index_js_1.Server({
|
|
91
91
|
name: 'servicenow-machine-learning',
|
|
@@ -484,46 +484,68 @@ class ServiceNowMachineLearningMCP {
|
|
|
484
484
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
485
485
|
const { name, arguments: args } = request.params;
|
|
486
486
|
try {
|
|
487
|
+
// Start operation with token tracking
|
|
488
|
+
this.logger.operationStart(name, args);
|
|
489
|
+
let result;
|
|
487
490
|
switch (name) {
|
|
488
491
|
// Training
|
|
489
492
|
case 'ml_train_incident_classifier':
|
|
490
|
-
|
|
493
|
+
result = await this.trainIncidentClassifier(args);
|
|
494
|
+
break;
|
|
491
495
|
case 'ml_train_change_risk':
|
|
492
|
-
|
|
496
|
+
result = await this.trainChangeRiskModel(args);
|
|
497
|
+
break;
|
|
493
498
|
case 'ml_train_anomaly_detector':
|
|
494
|
-
|
|
499
|
+
result = await this.trainAnomalyDetector(args);
|
|
500
|
+
break;
|
|
495
501
|
// Prediction
|
|
496
502
|
case 'ml_classify_incident':
|
|
497
|
-
|
|
503
|
+
result = await this.classifyIncident(args);
|
|
504
|
+
break;
|
|
498
505
|
case 'ml_predict_change_risk':
|
|
499
|
-
|
|
506
|
+
result = await this.predictChangeRisk(args);
|
|
507
|
+
break;
|
|
500
508
|
case 'ml_forecast_incidents':
|
|
501
|
-
|
|
509
|
+
result = await this.forecastIncidents(args);
|
|
510
|
+
break;
|
|
502
511
|
case 'ml_detect_anomalies':
|
|
503
|
-
|
|
512
|
+
result = await this.detectAnomalies(args);
|
|
513
|
+
break;
|
|
504
514
|
// Management
|
|
505
515
|
case 'ml_model_status':
|
|
506
|
-
|
|
516
|
+
result = await this.getModelStatus(args);
|
|
517
|
+
break;
|
|
507
518
|
case 'ml_evaluate_model':
|
|
508
|
-
|
|
519
|
+
result = await this.evaluateModel(args);
|
|
520
|
+
break;
|
|
509
521
|
// ServiceNow Native ML
|
|
510
522
|
case 'ml_performance_analytics':
|
|
511
|
-
|
|
523
|
+
result = await this.performanceAnalytics(args);
|
|
524
|
+
break;
|
|
512
525
|
case 'ml_predictive_intelligence':
|
|
513
|
-
|
|
526
|
+
result = await this.predictiveIntelligence(args);
|
|
527
|
+
break;
|
|
514
528
|
case 'ml_agent_intelligence':
|
|
515
|
-
|
|
529
|
+
result = await this.agentIntelligence(args);
|
|
530
|
+
break;
|
|
516
531
|
case 'ml_process_optimization':
|
|
517
|
-
|
|
532
|
+
result = await this.processOptimization(args);
|
|
533
|
+
break;
|
|
518
534
|
case 'ml_virtual_agent_nlu':
|
|
519
|
-
|
|
535
|
+
result = await this.virtualAgentNLU(args);
|
|
536
|
+
break;
|
|
520
537
|
case 'ml_hybrid_recommendation':
|
|
521
|
-
|
|
538
|
+
result = await this.hybridRecommendation(args);
|
|
539
|
+
break;
|
|
522
540
|
default:
|
|
523
541
|
throw new Error(`Unknown tool: ${name}`);
|
|
524
542
|
}
|
|
543
|
+
// Complete operation with token tracking
|
|
544
|
+
this.logger.operationComplete(name, result);
|
|
545
|
+
return result;
|
|
525
546
|
}
|
|
526
547
|
catch (error) {
|
|
548
|
+
this.logger.error(`ML tool execution failed: ${name}`, error);
|
|
527
549
|
return {
|
|
528
550
|
content: [{
|
|
529
551
|
type: 'text',
|
|
@@ -589,6 +611,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
589
611
|
}
|
|
590
612
|
catch (aggError) {
|
|
591
613
|
// Final fallback: Estimate based on a sample
|
|
614
|
+
this.logger.trackAPICall('SEARCH', 'incident', 1000);
|
|
592
615
|
const sampleResult = await this.client.searchRecords('incident', countQuery, 1000);
|
|
593
616
|
if (sampleResult.success && sampleResult.data?.result) {
|
|
594
617
|
totalAvailable = sampleResult.data.result.length >= 1000 ? 5000 : sampleResult.data.result.length;
|
|
@@ -1784,6 +1807,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
1784
1807
|
if (toolName === 'snow_query_table') {
|
|
1785
1808
|
const { table, query: q, limit: l, fields, include_content } = args;
|
|
1786
1809
|
// Use the client to fetch data
|
|
1810
|
+
this.logger.trackAPICall('SEARCH', table, l || 100);
|
|
1787
1811
|
const response = await this.client.searchRecords(table, q || '', l || 100);
|
|
1788
1812
|
if (!response.success) {
|
|
1789
1813
|
throw new Error(`Query failed: ${response.error}`);
|
|
@@ -2018,6 +2042,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
2018
2042
|
if (toolName === 'snow_query_table') {
|
|
2019
2043
|
const { table, query: q, limit: l, fields, include_content } = args;
|
|
2020
2044
|
// Use the client to fetch data
|
|
2045
|
+
this.logger.trackAPICall('SEARCH', table, l || 100);
|
|
2021
2046
|
const response = await this.client.searchRecords(table, q || '', l || 100);
|
|
2022
2047
|
if (!response.success) {
|
|
2023
2048
|
throw new Error(`Query failed: ${response.error}`);
|
|
@@ -3002,6 +3027,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
3002
3027
|
const tableName = tableMatch[1];
|
|
3003
3028
|
const query = params.sysparm_query || '';
|
|
3004
3029
|
const limit = params.sysparm_limit || 100;
|
|
3030
|
+
this.logger.trackAPICall('SEARCH', tableName, limit);
|
|
3005
3031
|
const response = await this.client.searchRecords(tableName, query, limit);
|
|
3006
3032
|
if (response.success) {
|
|
3007
3033
|
return {
|
|
@@ -3018,6 +3044,7 @@ class ServiceNowMachineLearningMCP {
|
|
|
3018
3044
|
const tableName = statsMatch[1];
|
|
3019
3045
|
const query = params.sysparm_query || '';
|
|
3020
3046
|
// Use a limit of 1 with count to get total
|
|
3047
|
+
this.logger.trackAPICall('SEARCH', tableName, 1);
|
|
3021
3048
|
const response = await this.client.searchRecords(tableName, query, 1);
|
|
3022
3049
|
if (response.success) {
|
|
3023
3050
|
// Estimate count based on response
|