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 ServiceNowPlatformDevelopmentMCP {
|
|
17
17
|
constructor() {
|
|
18
18
|
this.tableCache = new Map();
|
|
@@ -25,7 +25,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
27
|
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
28
|
-
this.logger = new
|
|
28
|
+
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowPlatformDevelopmentMCP');
|
|
29
29
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
30
30
|
this.setupHandlers();
|
|
31
31
|
}
|
|
@@ -172,33 +172,48 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
172
172
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
173
173
|
try {
|
|
174
174
|
const { name, arguments: args } = request.params;
|
|
175
|
+
// Start operation with token tracking
|
|
176
|
+
this.logger.operationStart(name, args);
|
|
175
177
|
// Ensure authentication
|
|
176
178
|
const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
177
179
|
if (!authResult.success) {
|
|
178
180
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required');
|
|
179
181
|
}
|
|
182
|
+
let result;
|
|
180
183
|
switch (name) {
|
|
181
184
|
case 'snow_create_ui_page':
|
|
182
|
-
|
|
185
|
+
result = await this.createUIPage(args);
|
|
186
|
+
break;
|
|
183
187
|
case 'snow_create_script_include':
|
|
184
|
-
|
|
188
|
+
result = await this.createScriptInclude(args);
|
|
189
|
+
break;
|
|
185
190
|
case 'snow_create_business_rule':
|
|
186
|
-
|
|
191
|
+
result = await this.createBusinessRule(args);
|
|
192
|
+
break;
|
|
187
193
|
case 'snow_create_client_script':
|
|
188
|
-
|
|
194
|
+
result = await this.createClientScript(args);
|
|
195
|
+
break;
|
|
189
196
|
case 'snow_create_ui_policy':
|
|
190
|
-
|
|
197
|
+
result = await this.createUIPolicy(args);
|
|
198
|
+
break;
|
|
191
199
|
case 'snow_create_ui_action':
|
|
192
|
-
|
|
200
|
+
result = await this.createUIAction(args);
|
|
201
|
+
break;
|
|
193
202
|
case 'snow_discover_platform_tables':
|
|
194
|
-
|
|
203
|
+
result = await this.discoverPlatformTables(args);
|
|
204
|
+
break;
|
|
195
205
|
case 'snow_discover_table_fields':
|
|
196
|
-
|
|
206
|
+
result = await this.discoverTableFields(args);
|
|
207
|
+
break;
|
|
197
208
|
case 'snow_table_schema_discovery':
|
|
198
|
-
|
|
209
|
+
result = await this.discoverTableSchema(args);
|
|
210
|
+
break;
|
|
199
211
|
default:
|
|
200
212
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
201
213
|
}
|
|
214
|
+
// Complete operation with token tracking
|
|
215
|
+
this.logger.operationComplete(name, result);
|
|
216
|
+
return result;
|
|
202
217
|
}
|
|
203
218
|
catch (error) {
|
|
204
219
|
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
@@ -224,6 +239,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
224
239
|
const discoveredTables = [];
|
|
225
240
|
for (const tableQuery of tableQueries) {
|
|
226
241
|
if (category === 'all' || category === tableQuery.category) {
|
|
242
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 50);
|
|
227
243
|
const tablesResponse = await this.client.searchRecords('sys_db_object', tableQuery.query, 50);
|
|
228
244
|
if (tablesResponse.success && tablesResponse.data) {
|
|
229
245
|
discoveredTables.push({
|
|
@@ -268,6 +284,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
268
284
|
}
|
|
269
285
|
// Get all fields for this table with CORRECT query syntax
|
|
270
286
|
// ✅ FIX: Use proper ServiceNow query for dictionary
|
|
287
|
+
this.logger.trackAPICall('SEARCH', 'sys_dictionary', 500);
|
|
271
288
|
const fieldsResponse = await this.client.searchRecords('sys_dictionary', `name=${tableInfo.name}^element!=NULL^ORname=${tableInfo.name}^elementISNOTEMPTY`, 500 // Increased limit for tables with many fields
|
|
272
289
|
);
|
|
273
290
|
if (!fieldsResponse.success || !fieldsResponse.data) {
|
|
@@ -361,6 +378,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
361
378
|
};
|
|
362
379
|
}
|
|
363
380
|
// Try direct lookup first
|
|
381
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 1);
|
|
364
382
|
const tableResponse = await this.client.searchRecords('sys_db_object', `name=${tableName}`, 1);
|
|
365
383
|
if (tableResponse.success && tableResponse.data?.result?.length > 0) {
|
|
366
384
|
const table = tableResponse.data.result[0];
|
|
@@ -373,6 +391,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
373
391
|
// Log the actual response for debugging
|
|
374
392
|
this.logger.debug(`Table lookup response for ${tableName}: ${JSON.stringify(tableResponse)}`);
|
|
375
393
|
// Try by sys_id
|
|
394
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 1);
|
|
376
395
|
const tableByIdResponse = await this.client.searchRecords('sys_db_object', `sys_id=${tableName}`, 1);
|
|
377
396
|
if (tableByIdResponse.success && tableByIdResponse.data?.result?.length > 0) {
|
|
378
397
|
const table = tableByIdResponse.data.result[0];
|
|
@@ -383,6 +402,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
383
402
|
};
|
|
384
403
|
}
|
|
385
404
|
// Try partial match
|
|
405
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 5);
|
|
386
406
|
const tableByPartialResponse = await this.client.searchRecords('sys_db_object', `nameCONTAINS${tableName}^ORlabelCONTAINS${tableName}`, 5);
|
|
387
407
|
if (tableByPartialResponse.success && tableByPartialResponse.data?.result?.length > 0) {
|
|
388
408
|
const table = tableByPartialResponse.data.result[0];
|
|
@@ -418,6 +438,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
418
438
|
};
|
|
419
439
|
// Ensure we have Update Set
|
|
420
440
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
441
|
+
this.logger.trackAPICall('CREATE', 'sys_ui_page', 1);
|
|
421
442
|
const response = await this.client.createRecord('sys_ui_page', uiPageData);
|
|
422
443
|
if (!response.success) {
|
|
423
444
|
throw new Error(`Failed to create UI Page: ${response.error}`);
|
|
@@ -448,6 +469,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
448
469
|
api_name: args.apiName || args.name
|
|
449
470
|
};
|
|
450
471
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
472
|
+
this.logger.trackAPICall('CREATE', 'sys_script_include', 1);
|
|
451
473
|
const response = await this.client.createRecord('sys_script_include', scriptIncludeData);
|
|
452
474
|
if (!response.success) {
|
|
453
475
|
throw new Error(`Failed to create Script Include: ${response.error}`);
|
|
@@ -484,6 +506,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
484
506
|
description: args.description || ''
|
|
485
507
|
};
|
|
486
508
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
509
|
+
this.logger.trackAPICall('CREATE', 'sys_script', 1);
|
|
487
510
|
const response = await this.client.createRecord('sys_script', businessRuleData);
|
|
488
511
|
if (!response.success) {
|
|
489
512
|
throw new Error(`Failed to create Business Rule: ${response.error}`);
|
|
@@ -520,6 +543,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
520
543
|
description: args.description || ''
|
|
521
544
|
};
|
|
522
545
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
546
|
+
this.logger.trackAPICall('CREATE', 'sys_script_client', 1);
|
|
523
547
|
const response = await this.client.createRecord('sys_script_client', clientScriptData);
|
|
524
548
|
if (!response.success) {
|
|
525
549
|
throw new Error(`Failed to create Client Script: ${response.error}`);
|
|
@@ -555,6 +579,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
555
579
|
reverse_if_false: args.reverseWhenFalse || false
|
|
556
580
|
};
|
|
557
581
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
582
|
+
this.logger.trackAPICall('CREATE', 'sys_ui_policy', 1);
|
|
558
583
|
const response = await this.client.createRecord('sys_ui_policy', uiPolicyData);
|
|
559
584
|
if (!response.success) {
|
|
560
585
|
throw new Error(`Failed to create UI Policy: ${response.error}`);
|
|
@@ -592,6 +617,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
592
617
|
description: args.description || ''
|
|
593
618
|
};
|
|
594
619
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
620
|
+
this.logger.trackAPICall('CREATE', 'sys_ui_action', 1);
|
|
595
621
|
const response = await this.client.createRecord('sys_ui_action', uiActionData);
|
|
596
622
|
if (!response.success) {
|
|
597
623
|
throw new Error(`Failed to create UI Action: ${response.error}`);
|
|
@@ -613,6 +639,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
613
639
|
*/
|
|
614
640
|
async discoverRequiredFields(tableName) {
|
|
615
641
|
try {
|
|
642
|
+
this.logger.trackAPICall('SEARCH', 'sys_dictionary', 50);
|
|
616
643
|
const fieldsResponse = await this.client.searchRecords('sys_dictionary', `nameSTARTSWITH${tableName}^element!=NULL^mandatory=true`, 50);
|
|
617
644
|
if (fieldsResponse.success && fieldsResponse.data) {
|
|
618
645
|
return fieldsResponse.data.result.map((field) => field.element);
|
|
@@ -647,6 +674,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
647
674
|
const isStandardTable = tableInfo.sys_id.startsWith('standard_table_');
|
|
648
675
|
let tableDetailsResponse = { success: false };
|
|
649
676
|
if (!isStandardTable) {
|
|
677
|
+
this.logger.trackAPICall('GET', 'sys_db_object', 1);
|
|
650
678
|
tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
|
|
651
679
|
}
|
|
652
680
|
// Declare the variable once with proper type
|
|
@@ -676,6 +704,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
676
704
|
tableDetails = tableDetailsResponse.data;
|
|
677
705
|
}
|
|
678
706
|
// Get all fields with detailed information
|
|
707
|
+
this.logger.trackAPICall('SEARCH', 'sys_dictionary', 200);
|
|
679
708
|
const fieldsResponse = await this.client.searchRecords('sys_dictionary', `name=${tableInfo.name}^element!=NULL`, 200);
|
|
680
709
|
if (!fieldsResponse.success || !fieldsResponse.data) {
|
|
681
710
|
const errorMessage = fieldsResponse.error ||
|
|
@@ -722,6 +751,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
722
751
|
extensionModel: tableDetails.extension_model
|
|
723
752
|
};
|
|
724
753
|
// Find tables that extend this one
|
|
754
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 50);
|
|
725
755
|
const childTablesResponse = await this.client.searchRecords('sys_db_object', `super_class=${tableInfo.sys_id}`, 50);
|
|
726
756
|
if (childTablesResponse.success && childTablesResponse.data) {
|
|
727
757
|
hierarchy.extendedBy = childTablesResponse.data.result.map((child) => ({
|
|
@@ -734,6 +764,7 @@ class ServiceNowPlatformDevelopmentMCP {
|
|
|
734
764
|
// Get indexes if requested
|
|
735
765
|
let indexes = [];
|
|
736
766
|
if (includeIndexes) {
|
|
767
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_index', 50);
|
|
737
768
|
const indexResponse = await this.client.searchRecords('sys_db_index', `table=${tableInfo.sys_id}`, 50);
|
|
738
769
|
if (indexResponse.success && indexResponse.data) {
|
|
739
770
|
indexes = indexResponse.data.result.map((index) => ({
|
|
@@ -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
|
const anti_mock_data_validator_js_1 = require("../utils/anti-mock-data-validator.js");
|
|
17
17
|
class ServiceNowReportingAnalyticsMCP {
|
|
18
18
|
constructor() {
|
|
@@ -25,7 +25,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
27
|
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
28
|
-
this.logger = new
|
|
28
|
+
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowReportingAnalyticsMCP');
|
|
29
29
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
30
30
|
this.setupHandlers();
|
|
31
31
|
}
|
|
@@ -215,36 +215,53 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
215
215
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
216
216
|
try {
|
|
217
217
|
const { name, arguments: args } = request.params;
|
|
218
|
+
// Start operation with token tracking
|
|
219
|
+
this.logger.operationStart(name, args);
|
|
218
220
|
const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
219
221
|
if (!authResult.success) {
|
|
220
222
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required');
|
|
221
223
|
}
|
|
224
|
+
let result;
|
|
222
225
|
switch (name) {
|
|
223
226
|
case 'snow_create_report':
|
|
224
|
-
|
|
227
|
+
result = await this.createReport(args);
|
|
228
|
+
break;
|
|
225
229
|
case 'snow_create_dashboard':
|
|
226
|
-
|
|
230
|
+
result = await this.createDashboard(args);
|
|
231
|
+
break;
|
|
227
232
|
case 'snow_create_kpi':
|
|
228
|
-
|
|
233
|
+
result = await this.createKPI(args);
|
|
234
|
+
break;
|
|
229
235
|
case 'snow_create_data_visualization':
|
|
230
|
-
|
|
236
|
+
result = await this.createDataVisualization(args);
|
|
237
|
+
break;
|
|
231
238
|
case 'snow_create_performance_analytics':
|
|
232
|
-
|
|
239
|
+
result = await this.createPerformanceAnalytics(args);
|
|
240
|
+
break;
|
|
233
241
|
case 'snow_create_scheduled_report':
|
|
234
|
-
|
|
242
|
+
result = await this.createScheduledReport(args);
|
|
243
|
+
break;
|
|
235
244
|
case 'snow_discover_reporting_tables':
|
|
236
|
-
|
|
245
|
+
result = await this.discoverReportingTables(args);
|
|
246
|
+
break;
|
|
237
247
|
case 'snow_discover_report_fields':
|
|
238
|
-
|
|
248
|
+
result = await this.discoverReportFields(args);
|
|
249
|
+
break;
|
|
239
250
|
case 'snow_analyze_data_quality':
|
|
240
|
-
|
|
251
|
+
result = await this.analyzeDataQuality(args);
|
|
252
|
+
break;
|
|
241
253
|
case 'snow_generate_insights':
|
|
242
|
-
|
|
254
|
+
result = await this.generateInsights(args);
|
|
255
|
+
break;
|
|
243
256
|
case 'snow_export_report_data':
|
|
244
|
-
|
|
257
|
+
result = await this.exportReportData(args);
|
|
258
|
+
break;
|
|
245
259
|
default:
|
|
246
260
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
247
261
|
}
|
|
262
|
+
// Complete operation with token tracking
|
|
263
|
+
this.logger.operationComplete(name, result);
|
|
264
|
+
return result;
|
|
248
265
|
}
|
|
249
266
|
catch (error) {
|
|
250
267
|
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
@@ -295,6 +312,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
295
312
|
...aggregateConfig
|
|
296
313
|
};
|
|
297
314
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
315
|
+
this.logger.trackAPICall('CREATE', 'sys_report', 1);
|
|
298
316
|
const response = await this.client.createRecord('sys_report', reportData);
|
|
299
317
|
if (!response.success) {
|
|
300
318
|
throw new Error(`Failed to create Report: ${response.error}`);
|
|
@@ -324,6 +342,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
324
342
|
const layouts = await this.getDashboardLayouts();
|
|
325
343
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
326
344
|
// Try Performance Analytics dashboard first (pa_dashboards)
|
|
345
|
+
this.logger.trackAPICall('CREATE', 'pa_dashboards', 1);
|
|
327
346
|
let response = await this.client.createRecord('pa_dashboards', {
|
|
328
347
|
name: args.name,
|
|
329
348
|
title: args.name,
|
|
@@ -431,6 +450,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
431
450
|
};
|
|
432
451
|
const updateSetResult = await this.client.ensureUpdateSet();
|
|
433
452
|
// Try pa_indicators (Performance Analytics) for KPIs
|
|
453
|
+
this.logger.trackAPICall('CREATE', 'pa_indicators', 1);
|
|
434
454
|
let response = await this.client.createRecord('pa_indicators', {
|
|
435
455
|
name: args.name,
|
|
436
456
|
label: args.name,
|
|
@@ -672,6 +692,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
672
692
|
if (args?.category) {
|
|
673
693
|
query = `sys_class_name=${args.category}`;
|
|
674
694
|
}
|
|
695
|
+
this.logger.trackAPICall('SEARCH', 'sys_db_object', 100);
|
|
675
696
|
const tables = await this.client.searchRecords('sys_db_object', query, 100);
|
|
676
697
|
if (!tables.success) {
|
|
677
698
|
throw new Error('Failed to discover reporting tables');
|
|
@@ -720,6 +741,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
720
741
|
if (args.fieldType) {
|
|
721
742
|
query += `^internal_type=${args.fieldType}`;
|
|
722
743
|
}
|
|
744
|
+
this.logger.trackAPICall('SEARCH', 'sys_dictionary', 100);
|
|
723
745
|
const fields = await this.client.searchRecords('sys_dictionary', query, 100);
|
|
724
746
|
if (!fields.success) {
|
|
725
747
|
throw new Error('Failed to discover report fields');
|
|
@@ -756,6 +778,7 @@ class ServiceNowReportingAnalyticsMCP {
|
|
|
756
778
|
throw new Error(`Table not found: ${args.table}`);
|
|
757
779
|
}
|
|
758
780
|
// Get REAL data for analysis (increased from sample to comprehensive dataset)
|
|
781
|
+
this.logger.trackAPICall('SEARCH', args.table, 1000);
|
|
759
782
|
const sampleData = await this.client.searchRecords(args.table, '', 1000); // Get up to 1000 records for REAL analysis
|
|
760
783
|
if (!sampleData.success) {
|
|
761
784
|
throw new Error('Failed to retrieve sample data');
|
|
@@ -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 ServiceNowSecurityComplianceMCP {
|
|
17
17
|
constructor() {
|
|
18
18
|
this.server = new index_js_1.Server({
|
|
@@ -24,7 +24,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
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('ServiceNowSecurityComplianceMCP');
|
|
28
28
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
29
29
|
this.setupHandlers();
|
|
30
30
|
}
|
|
@@ -199,36 +199,53 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
199
199
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
200
200
|
try {
|
|
201
201
|
const { name, arguments: args } = request.params;
|
|
202
|
+
// Start operation with token tracking
|
|
203
|
+
this.logger.operationStart(name, args);
|
|
202
204
|
const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
203
205
|
if (!authResult.success) {
|
|
204
206
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required');
|
|
205
207
|
}
|
|
208
|
+
let result;
|
|
206
209
|
switch (name) {
|
|
207
210
|
case 'snow_create_security_policy':
|
|
208
|
-
|
|
211
|
+
result = await this.createSecurityPolicy(args);
|
|
212
|
+
break;
|
|
209
213
|
case 'snow_create_compliance_rule':
|
|
210
|
-
|
|
214
|
+
result = await this.createComplianceRule(args);
|
|
215
|
+
break;
|
|
211
216
|
case 'snow_create_audit_rule':
|
|
212
|
-
|
|
217
|
+
result = await this.createAuditRule(args);
|
|
218
|
+
break;
|
|
213
219
|
case 'snow_create_access_control':
|
|
214
|
-
|
|
220
|
+
result = await this.createAccessControl(args);
|
|
221
|
+
break;
|
|
215
222
|
case 'snow_create_data_policy':
|
|
216
|
-
|
|
223
|
+
result = await this.createDataPolicy(args);
|
|
224
|
+
break;
|
|
217
225
|
case 'snow_create_vulnerability_scan':
|
|
218
|
-
|
|
226
|
+
result = await this.createVulnerabilityScan(args);
|
|
227
|
+
break;
|
|
219
228
|
case 'snow_discover_security_frameworks':
|
|
220
|
-
|
|
229
|
+
result = await this.discoverSecurityFrameworks(args);
|
|
230
|
+
break;
|
|
221
231
|
case 'snow_discover_security_policies':
|
|
222
|
-
|
|
232
|
+
result = await this.discoverSecurityPolicies(args);
|
|
233
|
+
break;
|
|
223
234
|
case 'snow_run_compliance_scan':
|
|
224
|
-
|
|
235
|
+
result = await this.runComplianceScan(args);
|
|
236
|
+
break;
|
|
225
237
|
case 'snow_audit_trail__analysis':
|
|
226
|
-
|
|
238
|
+
result = await this.auditTrailAnalysis(args);
|
|
239
|
+
break;
|
|
227
240
|
case 'snow_security_risk_assessment':
|
|
228
|
-
|
|
241
|
+
result = await this.securityRiskAssessment(args);
|
|
242
|
+
break;
|
|
229
243
|
default:
|
|
230
244
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
231
245
|
}
|
|
246
|
+
// Complete operation with token tracking
|
|
247
|
+
this.logger.operationComplete(name, result);
|
|
248
|
+
return result;
|
|
232
249
|
}
|
|
233
250
|
catch (error) {
|
|
234
251
|
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
@@ -266,6 +283,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
266
283
|
];
|
|
267
284
|
for (const tableName of possibleTables) {
|
|
268
285
|
try {
|
|
286
|
+
this.logger.trackAPICall('CREATE', tableName, 1);
|
|
269
287
|
response = await this.client.createRecord(tableName, policyData);
|
|
270
288
|
if (response.success) {
|
|
271
289
|
this.logger.info(`Security policy created in table: ${tableName}`);
|
|
@@ -636,6 +654,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
636
654
|
const frameworks = [];
|
|
637
655
|
// Discover Security Frameworks
|
|
638
656
|
if (type === 'all' || type === 'security') {
|
|
657
|
+
this.logger.trackAPICall('SEARCH', 'sys_security_framework', 50);
|
|
639
658
|
const securityFrameworks = await this.client.searchRecords('sys_security_framework', '', 50);
|
|
640
659
|
if (securityFrameworks.success) {
|
|
641
660
|
frameworks.push({
|
|
@@ -651,6 +670,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
651
670
|
}
|
|
652
671
|
// Discover Compliance Frameworks
|
|
653
672
|
if (type === 'all' || type === 'compliance') {
|
|
673
|
+
this.logger.trackAPICall('SEARCH', 'sys_compliance_framework', 50);
|
|
654
674
|
const complianceFrameworks = await this.client.searchRecords('sys_compliance_framework', '', 50);
|
|
655
675
|
if (complianceFrameworks.success) {
|
|
656
676
|
frameworks.push({
|
|
@@ -689,6 +709,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
689
709
|
if (args?.active !== undefined) {
|
|
690
710
|
query += query ? `^active=${args.active}` : `active=${args.active}`;
|
|
691
711
|
}
|
|
712
|
+
this.logger.trackAPICall('SEARCH', 'sys_security_policy', 50);
|
|
692
713
|
const policies = await this.client.searchRecords('sys_security_policy', query, 50);
|
|
693
714
|
if (!policies.success) {
|
|
694
715
|
throw new Error('Failed to discover security policies');
|
|
@@ -764,6 +785,7 @@ class ServiceNowSecurityComplianceMCP {
|
|
|
764
785
|
if (args?.table) {
|
|
765
786
|
query += query ? `^table=${args.table}` : `table=${args.table}`;
|
|
766
787
|
}
|
|
788
|
+
this.logger.trackAPICall('SEARCH', 'sys_audit', 100);
|
|
767
789
|
const auditRecords = await this.client.searchRecords('sys_audit', query, 100);
|
|
768
790
|
if (!auditRecords.success) {
|
|
769
791
|
throw new Error('Failed to retrieve audit records');
|