snow-flow 3.4.19 → 3.4.21

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.
@@ -516,6 +516,8 @@ class ServiceNowAutomationMCP {
516
516
  }
517
517
  // Complete operation with token tracking
518
518
  this.logger.operationComplete(name, result);
519
+ // Add token usage to response
520
+ result = this.logger.addTokenUsageToResponse(result);
519
521
  return result;
520
522
  }
521
523
  catch (error) {
@@ -847,6 +847,8 @@ class ServiceNowOperationsMCP {
847
847
  }
848
848
  // Complete operation with token tracking
849
849
  this.logger.operationComplete(name, result);
850
+ // Add token usage to response
851
+ result = this.logger.addTokenUsageToResponse(result);
850
852
  return result;
851
853
  }
852
854
  catch (error) {
@@ -870,7 +872,7 @@ class ServiceNowOperationsMCP {
870
872
  query?.toLowerCase().includes('onboard') ||
871
873
  (fields && fields.length <= 2); // Minimal fields = analytics
872
874
  if (isAnalyticsContext) {
873
- logger.info(`šŸ“Š Analytics context detected - NO LIMIT applied for complete analysis`);
875
+ this.logger.info(`šŸ“Š Analytics context detected - NO LIMIT applied for complete analysis`);
874
876
  return undefined; // No limit - get ALL records
875
877
  }
876
878
  // šŸ¤– ML Training context
@@ -878,21 +880,21 @@ class ServiceNowOperationsMCP {
878
880
  query?.toLowerCase().includes('ml') ||
879
881
  table?.toLowerCase().includes('train');
880
882
  if (isMLContext) {
881
- logger.info(`🧠 ML context detected - using ML-optimized limit: 5000`);
883
+ this.logger.info(`🧠 ML context detected - using ML-optimized limit: 5000`);
882
884
  return 5000; // ML training needs substantial data
883
885
  }
884
886
  // šŸ“ˆ Count-only queries - efficient
885
887
  if (!includeContent) {
886
- logger.info(`šŸ“ˆ Count-only query - can handle large datasets efficiently`);
888
+ this.logger.info(`šŸ“ˆ Count-only query - can handle large datasets efficiently`);
887
889
  return 10000; // Count queries are very memory-efficient
888
890
  }
889
891
  // šŸ–„ļø Display context - limited data needed
890
892
  if (includeContent && fields && fields.length > 5) {
891
- logger.info(`šŸ–„ļø Display context detected - limiting to viewable records`);
893
+ this.logger.info(`šŸ–„ļø Display context detected - limiting to viewable records`);
892
894
  return 100; // Display queries need less data
893
895
  }
894
896
  // Default: moderate limit
895
- logger.info(`āš ļø No specific context detected - using conservative limit. Consider specifying limit for your use case!`);
897
+ this.logger.info(`āš ļø No specific context detected - using conservative limit. Consider specifying limit for your use case!`);
896
898
  return 500; // Conservative default
897
899
  };
898
900
  const { table, query = '', include_content = false, fields, include_display_values = false, group_by, order_by, offset = 0 // āœ… NEW: Support pagination!
@@ -910,9 +912,9 @@ class ServiceNowOperationsMCP {
910
912
  query?.toLowerCase().includes('ml') ||
911
913
  args.limit !== undefined && args.limit < 1000;
912
914
  if (isMLTrainingContext && limit < 1000) {
913
- logger.warn(`āš ļø ML Training detected with low limit (${limit}). Consider setting limit=5000+ for better training data!`);
915
+ this.logger.warn(`āš ļø ML Training detected with low limit (${limit}). Consider setting limit=5000+ for better training data!`);
914
916
  }
915
- logger.info(`Universal query on table '${table}' with: ${query} (limit: ${limit === undefined ? 'UNLIMITED' : limit}, offset: ${offset}, include_content: ${include_content})`);
917
+ this.logger.info(`Universal query on table '${table}' with: ${query} (limit: ${limit === undefined ? 'UNLIMITED' : limit}, offset: ${offset}, include_content: ${include_content})`);
916
918
  try {
917
919
  // Convert natural language to ServiceNow query if needed
918
920
  const processedQuery = this.processNaturalLanguageQuery(query || '', table);
@@ -957,7 +959,7 @@ class ServiceNowOperationsMCP {
957
959
  const exists = sampleRecord.hasOwnProperty(field) ||
958
960
  sampleRecord.hasOwnProperty(`${field}_display_value`);
959
961
  if (!exists) {
960
- logger.warn(`āš ļø Field '${field}' not found in table '${table}'`);
962
+ this.logger.warn(`āš ļø Field '${field}' not found in table '${table}'`);
961
963
  }
962
964
  return exists;
963
965
  });
@@ -1040,7 +1042,7 @@ class ServiceNowOperationsMCP {
1040
1042
  }
1041
1043
  catch (error) {
1042
1044
  // āœ… IMPROVED: Better error messages
1043
- logger.error(`Error querying ${table}:`, error);
1045
+ this.logger.error(`Error querying ${table}:`, error);
1044
1046
  if (error.code === 'ECONNREFUSED') {
1045
1047
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Cannot connect to ServiceNow. Please check your instance URL and network connection.`);
1046
1048
  }
@@ -1079,7 +1081,7 @@ class ServiceNowOperationsMCP {
1079
1081
  async handleQueryIncidents(args) {
1080
1082
  const { query, limit = 10, include__analysis = false, fields, include_content = false // šŸŽÆ NEW: Explicit control over returning full incident data
1081
1083
  } = args;
1082
- logger.info(`Querying incidents with: ${query} (include_content: ${include_content})`);
1084
+ this.logger.info(`Querying incidents with: ${query} (include_content: ${include_content})`);
1083
1085
  try {
1084
1086
  // Convert natural language to ServiceNow query if needed
1085
1087
  const processedQuery = this.processNaturalLanguageQuery(query, 'incident');
@@ -1137,13 +1139,13 @@ class ServiceNowOperationsMCP {
1137
1139
  };
1138
1140
  }
1139
1141
  catch (error) {
1140
- logger.error('Error querying incidents:', error);
1142
+ this.logger.error('Error querying incidents:', error);
1141
1143
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to query incidents: ${error}`);
1142
1144
  }
1143
1145
  }
1144
1146
  async handleAnalyzeIncident(args) {
1145
1147
  const { incident_id, include_similar = true, suggest_resolution = true } = args;
1146
- logger.info(`Analyzing incident: ${incident_id}`);
1148
+ this.logger.info(`Analyzing incident: ${incident_id}`);
1147
1149
  try {
1148
1150
  // Get incident details
1149
1151
  const incident = await this.getIncidentDetails(incident_id);
@@ -1162,13 +1164,13 @@ class ServiceNowOperationsMCP {
1162
1164
  };
1163
1165
  }
1164
1166
  catch (error) {
1165
- logger.error('Error analyzing incident:', error);
1167
+ this.logger.error('Error analyzing incident:', error);
1166
1168
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to analyze incident: ${error}`);
1167
1169
  }
1168
1170
  }
1169
1171
  async handleAutoResolveIncident(args) {
1170
1172
  const { incident_id, dry_run = true } = args;
1171
- logger.info(`Auto-resolving incident: ${incident_id} (dry_run: ${dry_run})`);
1173
+ this.logger.info(`Auto-resolving incident: ${incident_id} (dry_run: ${dry_run})`);
1172
1174
  try {
1173
1175
  // Get incident details
1174
1176
  const incident = await this.getIncidentDetails(incident_id);
@@ -1200,13 +1202,13 @@ class ServiceNowOperationsMCP {
1200
1202
  };
1201
1203
  }
1202
1204
  catch (error) {
1203
- logger.error('Error auto-resolving incident:', error);
1205
+ this.logger.error('Error auto-resolving incident:', error);
1204
1206
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to auto-resolve incident: ${error}`);
1205
1207
  }
1206
1208
  }
1207
1209
  async handleQueryRequests(args) {
1208
1210
  const { query, limit = 10, include_items = false } = args;
1209
- logger.info(`Querying requests with: ${query}`);
1211
+ this.logger.info(`Querying requests with: ${query}`);
1210
1212
  try {
1211
1213
  const processedQuery = this.processNaturalLanguageQuery(query, 'request');
1212
1214
  const requests = await this.client.searchRecords('sc_request', processedQuery, limit);
@@ -1229,13 +1231,13 @@ class ServiceNowOperationsMCP {
1229
1231
  };
1230
1232
  }
1231
1233
  catch (error) {
1232
- logger.error('Error querying requests:', error);
1234
+ this.logger.error('Error querying requests:', error);
1233
1235
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to query requests: ${error}`);
1234
1236
  }
1235
1237
  }
1236
1238
  async handleQueryProblems(args) {
1237
1239
  const { query, limit = 10, include_incidents = false } = args;
1238
- logger.info(`Querying problems with: ${query}`);
1240
+ this.logger.info(`Querying problems with: ${query}`);
1239
1241
  try {
1240
1242
  const processedQuery = this.processNaturalLanguageQuery(query, 'problem');
1241
1243
  const problems = await this.client.searchRecords('problem', processedQuery, limit);
@@ -1258,13 +1260,13 @@ class ServiceNowOperationsMCP {
1258
1260
  };
1259
1261
  }
1260
1262
  catch (error) {
1261
- logger.error('Error querying problems:', error);
1263
+ this.logger.error('Error querying problems:', error);
1262
1264
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to query problems: ${error}`);
1263
1265
  }
1264
1266
  }
1265
1267
  async handleCMDBSearch(args) {
1266
1268
  const { query, ci_type = 'any', limit = 10, include_relationships = false } = args;
1267
- logger.info(`Searching CMDB with: ${query}, type: ${ci_type}`);
1269
+ this.logger.info(`Searching CMDB with: ${query}, type: ${ci_type}`);
1268
1270
  try {
1269
1271
  const ciTable = ci_type === 'any' ? 'cmdb_ci' : operationalTableMapping[ci_type] || 'cmdb_ci';
1270
1272
  const processedQuery = this.processNaturalLanguageQuery(query, 'cmdb');
@@ -1289,13 +1291,13 @@ class ServiceNowOperationsMCP {
1289
1291
  };
1290
1292
  }
1291
1293
  catch (error) {
1292
- logger.error('Error searching CMDB:', error);
1294
+ this.logger.error('Error searching CMDB:', error);
1293
1295
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to search CMDB: ${error}`);
1294
1296
  }
1295
1297
  }
1296
1298
  async handleUserLookup(args) {
1297
1299
  const { identifier, include_roles = true, include_groups = true } = args;
1298
- logger.info(`Looking up user: ${identifier}`);
1300
+ this.logger.info(`Looking up user: ${identifier}`);
1299
1301
  try {
1300
1302
  // Try different user lookup strategies
1301
1303
  let userQuery = '';
@@ -1338,13 +1340,13 @@ class ServiceNowOperationsMCP {
1338
1340
  };
1339
1341
  }
1340
1342
  catch (error) {
1341
- logger.error('Error looking up user:', error);
1343
+ this.logger.error('Error looking up user:', error);
1342
1344
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to lookup user: ${error}`);
1343
1345
  }
1344
1346
  }
1345
1347
  async handleOperationalMetrics(args) {
1346
1348
  const { timeframe = 'week', metric_types = [] } = args;
1347
- logger.info(`Getting operational metrics for timeframe: ${timeframe}`);
1349
+ this.logger.info(`Getting operational metrics for timeframe: ${timeframe}`);
1348
1350
  try {
1349
1351
  const metrics = await this.calculateOperationalMetrics(timeframe, metric_types);
1350
1352
  return {
@@ -1357,13 +1359,13 @@ class ServiceNowOperationsMCP {
1357
1359
  };
1358
1360
  }
1359
1361
  catch (error) {
1360
- logger.error('Error getting operational metrics:', error);
1362
+ this.logger.error('Error getting operational metrics:', error);
1361
1363
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to get operational metrics: ${error}`);
1362
1364
  }
1363
1365
  }
1364
1366
  async handlePatternAnalysis(args) {
1365
1367
  const { analysis_type, timeframe = 'week' } = args;
1366
- logger.info(`Performing pattern _analysis: ${analysis_type} for ${timeframe}`);
1368
+ this.logger.info(`Performing pattern _analysis: ${analysis_type} for ${timeframe}`);
1367
1369
  try {
1368
1370
  const patterns = await this.analyzePatterns(analysis_type, timeframe);
1369
1371
  return {
@@ -1376,13 +1378,13 @@ class ServiceNowOperationsMCP {
1376
1378
  };
1377
1379
  }
1378
1380
  catch (error) {
1379
- logger.error('Error analyzing patterns:', error);
1381
+ this.logger.error('Error analyzing patterns:', error);
1380
1382
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to analyze patterns: ${error}`);
1381
1383
  }
1382
1384
  }
1383
1385
  async handleKnowledgeSearch(args) {
1384
1386
  const { query, match_incident, limit = 5 } = args;
1385
- logger.info(`Searching knowledge base with: ${query}`);
1387
+ this.logger.info(`Searching knowledge base with: ${query}`);
1386
1388
  try {
1387
1389
  const processedQuery = this.processNaturalLanguageQuery(query, 'knowledge');
1388
1390
  const articles = await this.client.searchRecords('kb_knowledge', processedQuery, limit);
@@ -1408,13 +1410,13 @@ class ServiceNowOperationsMCP {
1408
1410
  };
1409
1411
  }
1410
1412
  catch (error) {
1411
- logger.error('Error searching knowledge base:', error);
1413
+ this.logger.error('Error searching knowledge base:', error);
1412
1414
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to search knowledge base: ${error}`);
1413
1415
  }
1414
1416
  }
1415
1417
  async handlePredictiveAnalysis(args) {
1416
1418
  const { prediction_type, timeframe = 'week' } = args;
1417
- logger.info(`Performing predictive _analysis: ${prediction_type} for ${timeframe}`);
1419
+ this.logger.info(`Performing predictive _analysis: ${prediction_type} for ${timeframe}`);
1418
1420
  try {
1419
1421
  const predictions = await this.performPredictiveAnalysis(prediction_type, timeframe);
1420
1422
  return {
@@ -1427,7 +1429,7 @@ class ServiceNowOperationsMCP {
1427
1429
  };
1428
1430
  }
1429
1431
  catch (error) {
1430
- logger.error('Error performing predictive _analysis:', error);
1432
+ this.logger.error('Error performing predictive _analysis:', error);
1431
1433
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to perform predictive _analysis: ${error}`);
1432
1434
  }
1433
1435
  }
@@ -1437,7 +1439,7 @@ class ServiceNowOperationsMCP {
1437
1439
  const lowerQuery = query.toLowerCase();
1438
1440
  // If already a ServiceNow encoded query, return as-is
1439
1441
  if (query.includes('=') || query.includes('!=') || query.includes('^') || query.includes('LIKE')) {
1440
- logger.info(`Using raw ServiceNow query: ${query}`);
1442
+ this.logger.info(`Using raw ServiceNow query: ${query}`);
1441
1443
  return query;
1442
1444
  }
1443
1445
  // Common ServiceNow query patterns
@@ -1610,7 +1612,7 @@ class ServiceNowOperationsMCP {
1610
1612
  for (const action of actions) {
1611
1613
  try {
1612
1614
  // This would integrate with actual automation systems
1613
- logger.info(`Executing action: ${action} for incident ${incident_id}`);
1615
+ this.logger.info(`Executing action: ${action} for incident ${incident_id}`);
1614
1616
  executed.push(`āœ… ${action}`);
1615
1617
  }
1616
1618
  catch (error) {
@@ -1651,7 +1653,7 @@ class ServiceNowOperationsMCP {
1651
1653
  });
1652
1654
  }
1653
1655
  catch (error) {
1654
- logger.error(`Error getting relationships for CI ${ci.sys_id}:`, error);
1656
+ this.logger.error(`Error getting relationships for CI ${ci.sys_id}:`, error);
1655
1657
  }
1656
1658
  }
1657
1659
  return relationships;
@@ -1700,7 +1702,7 @@ class ServiceNowOperationsMCP {
1700
1702
  .map(([category, count]) => `${category}: ${count}`);
1701
1703
  }
1702
1704
  catch (error) {
1703
- logger.error('Error calculating operational metrics:', error);
1705
+ this.logger.error('Error calculating operational metrics:', error);
1704
1706
  }
1705
1707
  return metrics;
1706
1708
  }
@@ -2109,7 +2111,7 @@ class ServiceNowOperationsMCP {
2109
2111
  }
2110
2112
  async handleCatalogItemManager(args) {
2111
2113
  const { action, item_id, ...params } = args;
2112
- logger.info(`Catalog item manager action: ${action}`, { item_id, params });
2114
+ this.logger.info(`Catalog item manager action: ${action}`, { item_id, params });
2113
2115
  try {
2114
2116
  switch (action) {
2115
2117
  case 'create': {
@@ -2121,13 +2123,13 @@ class ServiceNowOperationsMCP {
2121
2123
  const defaultCatalogResult = await this.client.searchRecords('sc_catalog', 'active=true^ORDERBYsys_created_on', 1);
2122
2124
  if (defaultCatalogResult.success && defaultCatalogResult.data?.result?.length > 0) {
2123
2125
  catalogId = defaultCatalogResult.data.result[0].sys_id;
2124
- logger.info('Using default catalog:', {
2126
+ this.logger.info('Using default catalog:', {
2125
2127
  catalogId,
2126
2128
  catalogName: defaultCatalogResult.data.result[0].title
2127
2129
  });
2128
2130
  }
2129
2131
  else {
2130
- logger.warn('No catalogs found, catalog item may not be visible');
2132
+ this.logger.warn('No catalogs found, catalog item may not be visible');
2131
2133
  }
2132
2134
  }
2133
2135
  if (!categoryId) {
@@ -2135,7 +2137,7 @@ class ServiceNowOperationsMCP {
2135
2137
  const defaultCategoryResult = await this.client.searchRecords('sc_category', 'active=true^titleLIKEHardware^ORtitleLIKEGeneral^ORtitleLIKEIT^ORDERBYsys_created_on', 1);
2136
2138
  if (defaultCategoryResult.success && defaultCategoryResult.data?.result?.length > 0) {
2137
2139
  categoryId = defaultCategoryResult.data.result[0].sys_id;
2138
- logger.info('Using default category:', {
2140
+ this.logger.info('Using default category:', {
2139
2141
  categoryId,
2140
2142
  categoryName: defaultCategoryResult.data.result[0].title
2141
2143
  });
@@ -2323,7 +2325,7 @@ class ServiceNowOperationsMCP {
2323
2325
  }
2324
2326
  }
2325
2327
  catch (error) {
2326
- logger.error('Error in catalog item manager:', error);
2328
+ this.logger.error('Error in catalog item manager:', error);
2327
2329
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Catalog item manager error: ${error}`);
2328
2330
  }
2329
2331
  }
@@ -2358,7 +2360,7 @@ class ServiceNowOperationsMCP {
2358
2360
  }
2359
2361
  async handleCatalogItemSearch(args) {
2360
2362
  const { query, include_inactive = false, fuzzy_match = true, category_filter, limit = 50, include_variables = false } = args;
2361
- logger.info(`Searching catalog items for: ${query}`, { fuzzy_match, category_filter, limit });
2363
+ this.logger.info(`Searching catalog items for: ${query}`, { fuzzy_match, category_filter, limit });
2362
2364
  try {
2363
2365
  // Build search queries
2364
2366
  const searchQueries = [];
@@ -2497,7 +2499,7 @@ class ServiceNowOperationsMCP {
2497
2499
  };
2498
2500
  }
2499
2501
  catch (error) {
2500
- logger.error('Error searching catalog items:', error);
2502
+ this.logger.error('Error searching catalog items:', error);
2501
2503
  throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Catalog search error: ${error}`);
2502
2504
  }
2503
2505
  }
@@ -2628,7 +2630,7 @@ class ServiceNowOperationsMCP {
2628
2630
  }
2629
2631
  async handleCleanupTestArtifacts(args) {
2630
2632
  const { artifact_types = ['catalog_items', 'flows', 'users'], test_patterns = ['Test%', 'Mock%', 'Demo%', '%_test_%', '%test', '%mock'], max_age_hours = 1, dry_run = false, preserve_update_set_entries = true, update_set_filter } = args;
2631
- logger.info('Starting test artifact cleanup', {
2633
+ this.logger.info('Starting test artifact cleanup', {
2632
2634
  artifact_types,
2633
2635
  test_patterns,
2634
2636
  max_age_hours,
@@ -2737,7 +2739,7 @@ class ServiceNowOperationsMCP {
2737
2739
  };
2738
2740
  }
2739
2741
  catch (error) {
2740
- logger.error('Error during test artifact cleanup:', error);
2742
+ this.logger.error('Error during test artifact cleanup:', error);
2741
2743
  return {
2742
2744
  content: [{
2743
2745
  type: 'text',
@@ -2868,7 +2870,7 @@ class ServiceNowOperationsMCP {
2868
2870
  }
2869
2871
  async handleCreateUserGroup(args) {
2870
2872
  const { name, description, email, manager, parent, type, active = true } = args;
2871
- logger.info(`Creating user group: ${name}`);
2873
+ this.logger.info(`Creating user group: ${name}`);
2872
2874
  try {
2873
2875
  // Check if group already exists
2874
2876
  const existingGroup = await this.client.get('/api/now/table/sys_user_group', {
@@ -2901,7 +2903,7 @@ class ServiceNowOperationsMCP {
2901
2903
  groupData.manager = managerUser.sys_id;
2902
2904
  }
2903
2905
  else {
2904
- logger.warn(`Manager "${manager}" not found, creating group without manager`);
2906
+ this.logger.warn(`Manager "${manager}" not found, creating group without manager`);
2905
2907
  }
2906
2908
  }
2907
2909
  // Handle parent group lookup
@@ -2911,7 +2913,7 @@ class ServiceNowOperationsMCP {
2911
2913
  groupData.parent = parentGroup.sys_id;
2912
2914
  }
2913
2915
  else {
2914
- logger.warn(`Parent group "${parent}" not found, creating group without parent`);
2916
+ this.logger.warn(`Parent group "${parent}" not found, creating group without parent`);
2915
2917
  }
2916
2918
  }
2917
2919
  // Create the group
@@ -2940,7 +2942,7 @@ class ServiceNowOperationsMCP {
2940
2942
  }
2941
2943
  async handleCreateUser(args) {
2942
2944
  const { user_name, first_name, last_name, email, department, manager, phone, title, location, active = true, password } = args;
2943
- logger.info(`Creating user: ${user_name}`);
2945
+ this.logger.info(`Creating user: ${user_name}`);
2944
2946
  try {
2945
2947
  // Check if user already exists
2946
2948
  const existingUser = await this.client.get('/api/now/table/sys_user', {
@@ -2976,7 +2978,7 @@ class ServiceNowOperationsMCP {
2976
2978
  userData.manager = managerUser.sys_id;
2977
2979
  }
2978
2980
  else {
2979
- logger.warn(`Manager "${manager}" not found, creating user without manager`);
2981
+ this.logger.warn(`Manager "${manager}" not found, creating user without manager`);
2980
2982
  }
2981
2983
  }
2982
2984
  // Handle department lookup
@@ -2986,7 +2988,7 @@ class ServiceNowOperationsMCP {
2986
2988
  userData.department = dept.sys_id;
2987
2989
  }
2988
2990
  else {
2989
- logger.warn(`Department "${department}" not found, creating user without department`);
2991
+ this.logger.warn(`Department "${department}" not found, creating user without department`);
2990
2992
  }
2991
2993
  }
2992
2994
  // Handle location lookup
@@ -2996,7 +2998,7 @@ class ServiceNowOperationsMCP {
2996
2998
  userData.location = loc.sys_id;
2997
2999
  }
2998
3000
  else {
2999
- logger.warn(`Location "${location}" not found, creating user without location`);
3001
+ this.logger.warn(`Location "${location}" not found, creating user without location`);
3000
3002
  }
3001
3003
  }
3002
3004
  // Create the user
@@ -3025,7 +3027,7 @@ class ServiceNowOperationsMCP {
3025
3027
  }
3026
3028
  async handleAssignUserToGroup(args) {
3027
3029
  const { user, group } = args;
3028
- logger.info(`Assigning user ${user} to group ${group}`);
3030
+ this.logger.info(`Assigning user ${user} to group ${group}`);
3029
3031
  try {
3030
3032
  // Find the user
3031
3033
  const userRecord = await this.findUserBySysIdOrUsername(user);
@@ -3088,7 +3090,7 @@ class ServiceNowOperationsMCP {
3088
3090
  }
3089
3091
  async handleRemoveUserFromGroup(args) {
3090
3092
  const { user, group } = args;
3091
- logger.info(`Removing user ${user} from group ${group}`);
3093
+ this.logger.info(`Removing user ${user} from group ${group}`);
3092
3094
  try {
3093
3095
  // Find the user
3094
3096
  const userRecord = await this.findUserBySysIdOrUsername(user);
@@ -3143,7 +3145,7 @@ class ServiceNowOperationsMCP {
3143
3145
  }
3144
3146
  async handleListGroupMembers(args) {
3145
3147
  const { group, active_only = true } = args;
3146
- logger.info(`Listing members of group: ${group}`);
3148
+ this.logger.info(`Listing members of group: ${group}`);
3147
3149
  try {
3148
3150
  // Find the group
3149
3151
  const groupRecord = await this.findGroupBySysIdOrName(group);
@@ -3180,7 +3182,7 @@ class ServiceNowOperationsMCP {
3180
3182
  const u = member.user;
3181
3183
  // Defensive programming: check if user object exists and has required fields
3182
3184
  if (!u || !u.user_name) {
3183
- logger.warn(`Group member ${index + 1} has invalid user data:`, member);
3185
+ this.logger.warn(`Group member ${index + 1} has invalid user data:`, member);
3184
3186
  response += `${index + 1}. **Invalid User Data** - ${member.sys_id || 'Unknown ID'}\n\n`;
3185
3187
  return;
3186
3188
  }
@@ -3276,7 +3278,7 @@ class ServiceNowOperationsMCP {
3276
3278
  async run() {
3277
3279
  const transport = new stdio_js_1.StdioServerTransport();
3278
3280
  await this.server.connect(transport);
3279
- logger.info('ServiceNow Operations MCP Server started');
3281
+ this.logger.info('ServiceNow Operations MCP Server started');
3280
3282
  }
3281
3283
  }
3282
3284
  exports.ServiceNowOperationsMCP = ServiceNowOperationsMCP;
@@ -29,7 +29,7 @@ class ServiceNowSystemPropertiesMCP {
29
29
  },
30
30
  });
31
31
  this.client = new servicenow_client_js_1.ServiceNowClient();
32
- this.oauth = new snow_oauth_js_1.SnowOAuth();
32
+ this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
33
33
  this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowSystemProperties');
34
34
  this.setupHandlers();
35
35
  this.setupTools();
@@ -369,6 +369,8 @@ class ServiceNowSystemPropertiesMCP {
369
369
  }
370
370
  // Complete operation with token tracking
371
371
  this.logger.operationComplete(name, result);
372
+ // Add token usage to response
373
+ result = this.logger.addTokenUsageToResponse(result);
372
374
  return result;
373
375
  }
374
376
  catch (error) {
@@ -66,6 +66,11 @@ export declare class MCPLogger {
66
66
  * Get token usage
67
67
  */
68
68
  getTokenUsage(): TokenUsage;
69
+ /**
70
+ * Add token usage to MCP response
71
+ * Helper method to append token usage to tool response
72
+ */
73
+ addTokenUsageToResponse(result: any): any;
69
74
  /**
70
75
  * Reset token usage
71
76
  */
@@ -131,7 +131,8 @@ class MCPLogger {
131
131
  */
132
132
  operationStart(operation, params) {
133
133
  this.startTime = Date.now();
134
- this.info(`šŸš€ Starting: ${operation} (tokens reset)`, params);
134
+ this.resetTokens(); // Actually reset tokens when starting new operation!
135
+ this.info(`šŸš€ Starting: ${operation}`, params);
135
136
  }
136
137
  /**
137
138
  * Log operation complete
@@ -161,6 +162,21 @@ class MCPLogger {
161
162
  getTokenUsage() {
162
163
  return { ...this.tokenUsage };
163
164
  }
165
+ /**
166
+ * Add token usage to MCP response
167
+ * Helper method to append token usage to tool response
168
+ */
169
+ addTokenUsageToResponse(result) {
170
+ const tokenUsage = this.getTokenUsage();
171
+ if (result && result.content && Array.isArray(result.content) && tokenUsage.total > 0) {
172
+ // Append token usage info to the last content item
173
+ const lastContent = result.content[result.content.length - 1];
174
+ if (lastContent && lastContent.type === 'text') {
175
+ lastContent.text += `\n\nšŸ“Š Token Usage: ${tokenUsage.total} (Input: ${tokenUsage.input}, Output: ${tokenUsage.output})`;
176
+ }
177
+ }
178
+ return result;
179
+ }
164
180
  /**
165
181
  * Reset token usage
166
182
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.4.19",
3
+ "version": "3.4.21",
4
4
  "description": "ServiceNow development framework with MCP server integration. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides 17 MCP servers for complete ServiceNow operations including widget deployment with coherence validation, table operations, script execution, machine learning, advanced features, and comprehensive platform management.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",