snow-flow 1.1.82 → 1.1.83

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.
Files changed (80) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/.claude-flow/queen/queen-memory.db +0 -0
  3. package/CLAUDE.md +276 -972
  4. package/dist/mcp/base-mcp-server.d.ts +117 -0
  5. package/dist/mcp/base-mcp-server.d.ts.map +1 -0
  6. package/dist/mcp/base-mcp-server.js +351 -0
  7. package/dist/mcp/base-mcp-server.js.map +1 -0
  8. package/dist/mcp/example-refactored-server.d.ts +18 -0
  9. package/dist/mcp/example-refactored-server.d.ts.map +1 -0
  10. package/dist/mcp/example-refactored-server.js +58 -0
  11. package/dist/mcp/example-refactored-server.js.map +1 -0
  12. package/dist/mcp/servicenow-automation-mcp-refactored.d.ts +26 -0
  13. package/dist/mcp/servicenow-automation-mcp-refactored.d.ts.map +1 -0
  14. package/dist/mcp/servicenow-automation-mcp-refactored.js +552 -0
  15. package/dist/mcp/servicenow-automation-mcp-refactored.js.map +1 -0
  16. package/dist/mcp/servicenow-flow-composer-mcp-refactored.d.ts +25 -0
  17. package/dist/mcp/servicenow-flow-composer-mcp-refactored.d.ts.map +1 -0
  18. package/dist/mcp/servicenow-flow-composer-mcp-refactored.js +566 -0
  19. package/dist/mcp/servicenow-flow-composer-mcp-refactored.js.map +1 -0
  20. package/dist/mcp/servicenow-graph-memory-mcp-refactored.d.ts +32 -0
  21. package/dist/mcp/servicenow-graph-memory-mcp-refactored.d.ts.map +1 -0
  22. package/dist/mcp/servicenow-graph-memory-mcp-refactored.js +642 -0
  23. package/dist/mcp/servicenow-graph-memory-mcp-refactored.js.map +1 -0
  24. package/dist/mcp/servicenow-integration-mcp-refactored.d.ts +24 -0
  25. package/dist/mcp/servicenow-integration-mcp-refactored.d.ts.map +1 -0
  26. package/dist/mcp/servicenow-integration-mcp-refactored.js +521 -0
  27. package/dist/mcp/servicenow-integration-mcp-refactored.js.map +1 -0
  28. package/dist/mcp/servicenow-operations-mcp-refactored.d.ts +65 -0
  29. package/dist/mcp/servicenow-operations-mcp-refactored.d.ts.map +1 -0
  30. package/dist/mcp/servicenow-operations-mcp-refactored.js +1913 -0
  31. package/dist/mcp/servicenow-operations-mcp-refactored.js.map +1 -0
  32. package/dist/mcp/servicenow-platform-development-mcp-refactored.d.ts +25 -0
  33. package/dist/mcp/servicenow-platform-development-mcp-refactored.d.ts.map +1 -0
  34. package/dist/mcp/servicenow-platform-development-mcp-refactored.js +542 -0
  35. package/dist/mcp/servicenow-platform-development-mcp-refactored.js.map +1 -0
  36. package/dist/mcp/servicenow-reporting-analytics-mcp-refactored.d.ts +26 -0
  37. package/dist/mcp/servicenow-reporting-analytics-mcp-refactored.d.ts.map +1 -0
  38. package/dist/mcp/servicenow-reporting-analytics-mcp-refactored.js +646 -0
  39. package/dist/mcp/servicenow-reporting-analytics-mcp-refactored.js.map +1 -0
  40. package/dist/mcp/servicenow-security-compliance-mcp-refactored.d.ts +25 -0
  41. package/dist/mcp/servicenow-security-compliance-mcp-refactored.d.ts.map +1 -0
  42. package/dist/mcp/servicenow-security-compliance-mcp-refactored.js +600 -0
  43. package/dist/mcp/servicenow-security-compliance-mcp-refactored.js.map +1 -0
  44. package/dist/mcp/servicenow-update-set-mcp-refactored.d.ts +31 -0
  45. package/dist/mcp/servicenow-update-set-mcp-refactored.d.ts.map +1 -0
  46. package/dist/mcp/servicenow-update-set-mcp-refactored.js +658 -0
  47. package/dist/mcp/servicenow-update-set-mcp-refactored.js.map +1 -0
  48. package/dist/orchestrator/flow-composer.d.ts.map +1 -1
  49. package/dist/orchestrator/flow-composer.js +13 -30
  50. package/dist/orchestrator/flow-composer.js.map +1 -1
  51. package/dist/queen/advanced-integration-test.js +1 -1
  52. package/dist/queen/advanced-integration-test.js.map +1 -1
  53. package/dist/queen/mcp-execution-bridge.d.ts +111 -0
  54. package/dist/queen/mcp-execution-bridge.d.ts.map +1 -0
  55. package/dist/queen/mcp-execution-bridge.js +547 -0
  56. package/dist/queen/mcp-execution-bridge.js.map +1 -0
  57. package/dist/queen/queen-memory.d.ts +28 -0
  58. package/dist/queen/queen-memory.d.ts.map +1 -1
  59. package/dist/queen/queen-memory.js +75 -0
  60. package/dist/queen/queen-memory.js.map +1 -1
  61. package/dist/queen/servicenow-queen.d.ts +3 -1
  62. package/dist/queen/servicenow-queen.d.ts.map +1 -1
  63. package/dist/queen/servicenow-queen.js +93 -12
  64. package/dist/queen/servicenow-queen.js.map +1 -1
  65. package/dist/snow-flow-system.d.ts.map +1 -1
  66. package/dist/snow-flow-system.js +22 -11
  67. package/dist/snow-flow-system.js.map +1 -1
  68. package/dist/sparc/sparc-help.d.ts +2 -4
  69. package/dist/sparc/sparc-help.d.ts.map +1 -1
  70. package/dist/sparc/sparc-help.js +32 -290
  71. package/dist/sparc/sparc-help.js.map +1 -1
  72. package/dist/sparc/team-sparc.d.ts +4 -28
  73. package/dist/sparc/team-sparc.d.ts.map +1 -1
  74. package/dist/sparc/team-sparc.js +23 -201
  75. package/dist/sparc/team-sparc.js.map +1 -1
  76. package/dist/version.d.ts +11 -1
  77. package/dist/version.d.ts.map +1 -1
  78. package/dist/version.js +38 -1
  79. package/dist/version.js.map +1 -1
  80. package/package.json +1 -1
@@ -0,0 +1,1913 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * ServiceNow Operations MCP Server - REFACTORED
5
+ * Uses BaseMCPServer to eliminate code duplication
6
+ *
7
+ * Handles operational data queries, incident management, and intelligent analysis
8
+ * Features:
9
+ * - Incident, Request, Problem, Change management
10
+ * - CMDB and User management
11
+ * - Intelligent incident analysis and auto-resolution
12
+ * - Pattern recognition and root cause analysis
13
+ * - Knowledge base integration
14
+ * - Predictive analytics
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ServiceNowOperationsMCP = void 0;
18
+ const base_mcp_server_js_1 = require("./base-mcp-server.js");
19
+ // Operational table mappings for ServiceNow
20
+ const operationalTableMapping = {
21
+ // ITIL Core Processes
22
+ incident: 'incident',
23
+ request: 'sc_request',
24
+ request_item: 'sc_req_item',
25
+ problem: 'problem',
26
+ change_request: 'change_request',
27
+ // Service Catalog
28
+ catalog: 'sc_catalog',
29
+ catalog_item: 'sc_cat_item',
30
+ catalog_category: 'sc_category',
31
+ catalog_variable: 'item_option_new',
32
+ catalog_variable_set: 'io_set_item',
33
+ catalog_ui_policy: 'catalog_ui_policy',
34
+ catalog_client_script: 'catalog_script_client',
35
+ catalog_template: 'sc_template',
36
+ // Task Management
37
+ task: 'task',
38
+ incident_task: 'incident_task',
39
+ problem_task: 'problem_task',
40
+ change_task: 'change_task',
41
+ approval: 'sysapproval_approver',
42
+ // User & Group Management
43
+ user: 'sys_user',
44
+ user_group: 'sys_user_group',
45
+ user_role: 'sys_user_has_role',
46
+ // CMDB (Configuration Management Database)
47
+ configuration_item: 'cmdb_ci',
48
+ server: 'cmdb_ci_server',
49
+ application: 'cmdb_ci_application',
50
+ database: 'cmdb_ci_database',
51
+ network_device: 'cmdb_ci_network_device',
52
+ service: 'cmdb_ci_service',
53
+ // Knowledge Management
54
+ knowledge_base: 'kb_knowledge_base',
55
+ knowledge: 'kb_knowledge',
56
+ // Metrics & Analytics
57
+ metric: 'sys_metric',
58
+ metric_instance: 'sys_metric_instance',
59
+ // Notifications
60
+ notification: 'sysevent_email_action',
61
+ email_log: 'sys_email'
62
+ };
63
+ class ServiceNowOperationsMCP extends base_mcp_server_js_1.BaseMCPServer {
64
+ constructor() {
65
+ super({
66
+ name: 'servicenow-operations',
67
+ version: '2.0.0',
68
+ description: 'Operations management server with BaseMCPServer pattern'
69
+ });
70
+ }
71
+ setupTools() {
72
+ // Tools are set up via getTools() method
73
+ }
74
+ getTools() {
75
+ return [
76
+ {
77
+ name: 'snow_query_incidents',
78
+ description: 'Advanced incident querying with filters and analysis',
79
+ inputSchema: {
80
+ type: 'object',
81
+ properties: {
82
+ query: { type: 'string', description: 'ServiceNow encoded query or natural language description' },
83
+ fields: { type: 'array', items: { type: 'string' }, description: 'Specific fields to return' },
84
+ limit: { type: 'number', default: 10, description: 'Maximum number of results (default: 10)' },
85
+ include_analysis: { type: 'boolean', default: false, description: 'Include intelligent analysis of incidents' }
86
+ },
87
+ required: ['query']
88
+ }
89
+ },
90
+ {
91
+ name: 'snow_analyze_incident',
92
+ description: 'Intelligent analysis of a specific incident with auto-resolution suggestions',
93
+ inputSchema: {
94
+ type: 'object',
95
+ properties: {
96
+ incident_id: { type: 'string', description: 'Incident number or sys_id' },
97
+ include_similar: { type: 'boolean', default: true, description: 'Include similar incidents in analysis' },
98
+ suggest_resolution: { type: 'boolean', default: true, description: 'Generate automated resolution suggestions' }
99
+ },
100
+ required: ['incident_id']
101
+ }
102
+ },
103
+ {
104
+ name: 'snow_auto_resolve_incident',
105
+ description: 'Attempt automated resolution of technical incidents',
106
+ inputSchema: {
107
+ type: 'object',
108
+ properties: {
109
+ incident_id: { type: 'string', description: 'Incident number or sys_id' },
110
+ dry_run: { type: 'boolean', default: true, description: 'Preview actions without executing' }
111
+ },
112
+ required: ['incident_id']
113
+ }
114
+ },
115
+ {
116
+ name: 'snow_query_requests',
117
+ description: 'Query and analyze service requests',
118
+ inputSchema: {
119
+ type: 'object',
120
+ properties: {
121
+ query: { type: 'string', description: 'ServiceNow encoded query or natural language' },
122
+ include_items: { type: 'boolean', default: false, description: 'Include request items' },
123
+ limit: { type: 'number', default: 10, description: 'Maximum number of results' }
124
+ },
125
+ required: ['query']
126
+ }
127
+ },
128
+ {
129
+ name: 'snow_query_problems',
130
+ description: 'Query and analyze problems with root cause analysis',
131
+ inputSchema: {
132
+ type: 'object',
133
+ properties: {
134
+ query: { type: 'string', description: 'ServiceNow encoded query or natural language' },
135
+ include_incidents: { type: 'boolean', default: false, description: 'Include related incidents' },
136
+ limit: { type: 'number', default: 10, description: 'Maximum number of results' }
137
+ },
138
+ required: ['query']
139
+ }
140
+ },
141
+ {
142
+ name: 'snow_cmdb_search',
143
+ description: 'Search and analyze Configuration Items (CMDB)',
144
+ inputSchema: {
145
+ type: 'object',
146
+ properties: {
147
+ query: { type: 'string', description: 'Search query for configuration items' },
148
+ ci_type: {
149
+ type: 'string',
150
+ enum: ['server', 'application', 'database', 'network_device', 'service', 'any'],
151
+ description: 'Type of CI (server, application, service, etc.)'
152
+ },
153
+ include_relationships: { type: 'boolean', default: false, description: 'Include CI relationships' },
154
+ limit: { type: 'number', default: 10, description: 'Maximum number of results' }
155
+ },
156
+ required: ['query']
157
+ }
158
+ },
159
+ {
160
+ name: 'snow_user_lookup',
161
+ description: 'Lookup and analyze user information',
162
+ inputSchema: {
163
+ type: 'object',
164
+ properties: {
165
+ identifier: { type: 'string', description: 'User ID, email, or name' },
166
+ include_groups: { type: 'boolean', default: true, description: 'Include user groups' },
167
+ include_roles: { type: 'boolean', default: true, description: 'Include user roles' }
168
+ },
169
+ required: ['identifier']
170
+ }
171
+ },
172
+ {
173
+ name: 'snow_operational_metrics',
174
+ description: 'Get operational metrics and analytics',
175
+ inputSchema: {
176
+ type: 'object',
177
+ properties: {
178
+ timeframe: {
179
+ type: 'string',
180
+ enum: ['today', 'week', 'month', 'quarter'],
181
+ default: 'week',
182
+ description: 'Time period for metrics'
183
+ },
184
+ metric_types: { type: 'array', items: { type: 'string' }, description: 'Types of metrics to include' }
185
+ }
186
+ }
187
+ },
188
+ {
189
+ name: 'snow_pattern_analysis',
190
+ description: 'Analyze patterns in incidents, requests, and problems',
191
+ inputSchema: {
192
+ type: 'object',
193
+ properties: {
194
+ analysis_type: {
195
+ type: 'string',
196
+ enum: ['incident_patterns', 'request_trends', 'problem_root_causes', 'user_behavior'],
197
+ description: 'Type of pattern analysis'
198
+ },
199
+ timeframe: {
200
+ type: 'string',
201
+ enum: ['day', 'week', 'month', 'quarter'],
202
+ default: 'week',
203
+ description: 'Time period for analysis'
204
+ }
205
+ },
206
+ required: ['analysis_type']
207
+ }
208
+ },
209
+ {
210
+ name: 'snow_knowledge_search',
211
+ description: 'Search knowledge base articles with intelligent matching',
212
+ inputSchema: {
213
+ type: 'object',
214
+ properties: {
215
+ query: { type: 'string', description: 'Search query or incident description' },
216
+ match_incident: { type: 'string', description: 'Match knowledge to specific incident' },
217
+ limit: { type: 'number', default: 5, description: 'Maximum number of results' }
218
+ },
219
+ required: ['query']
220
+ }
221
+ },
222
+ {
223
+ name: 'snow_predictive_analysis',
224
+ description: 'Predictive analysis for potential issues and trends',
225
+ inputSchema: {
226
+ type: 'object',
227
+ properties: {
228
+ prediction_type: {
229
+ type: 'string',
230
+ enum: ['incident_volume', 'system_failure', 'resource_exhaustion', 'user_impact'],
231
+ description: 'Type of prediction'
232
+ },
233
+ timeframe: {
234
+ type: 'string',
235
+ enum: ['day', 'week', 'month'],
236
+ default: 'week',
237
+ description: 'Prediction timeframe'
238
+ }
239
+ },
240
+ required: ['prediction_type']
241
+ }
242
+ },
243
+ {
244
+ name: 'snow_catalog_item_manager',
245
+ description: 'Manage service catalog items - create, update, configure variables and workflows',
246
+ inputSchema: {
247
+ type: 'object',
248
+ properties: {
249
+ action: {
250
+ type: 'string',
251
+ enum: ['create', 'update', 'list', 'get', 'add_variable', 'set_workflow', 'publish', 'retire'],
252
+ description: 'Action to perform'
253
+ },
254
+ item_id: { type: 'string', description: 'Catalog item sys_id (for update/get actions)' },
255
+ name: { type: 'string', description: 'Catalog item name' },
256
+ short_description: { type: 'string', description: 'Short description' },
257
+ description: { type: 'string', description: 'Full description' },
258
+ category_id: { type: 'string', description: 'Category sys_id' },
259
+ price: { type: 'string', description: 'Item price (e.g., "100.00")' },
260
+ recurring_price: { type: 'string', description: 'Recurring price if applicable' },
261
+ active: { type: 'boolean', default: true, description: 'Whether the item is active' },
262
+ variables: {
263
+ type: 'array',
264
+ items: {
265
+ type: 'object',
266
+ properties: {
267
+ name: { type: 'string' },
268
+ label: { type: 'string' },
269
+ type: {
270
+ type: 'string',
271
+ enum: ['single_line_text', 'multi_line_text', 'select_box', 'checkbox', 'reference', 'date', 'datetime']
272
+ },
273
+ mandatory: { type: 'boolean' },
274
+ default_value: { type: 'string' },
275
+ choices: { type: 'array', items: { type: 'string' } }
276
+ }
277
+ },
278
+ description: 'Variables to add'
279
+ }
280
+ },
281
+ required: ['action']
282
+ }
283
+ },
284
+ {
285
+ name: 'snow_catalog_item_search',
286
+ description: 'Search for catalog items with intelligent matching and discovery',
287
+ inputSchema: {
288
+ type: 'object',
289
+ properties: {
290
+ query: { type: 'string', description: 'Search query (e.g., "iPhone", "laptop", "mobile device")' },
291
+ category_filter: { type: 'string', description: 'Filter by category name or sys_id' },
292
+ include_variables: { type: 'boolean', default: false, description: 'Include catalog item variables in results' },
293
+ include_inactive: { type: 'boolean', default: false, description: 'Include inactive catalog items' },
294
+ fuzzy_match: { type: 'boolean', default: true, description: 'Enable fuzzy matching for similar items' },
295
+ limit: { type: 'number', default: 50, description: 'Maximum results to return' }
296
+ },
297
+ required: ['query']
298
+ }
299
+ },
300
+ {
301
+ name: 'snow_test_flow_with_mock',
302
+ description: 'Test flows with mock data - create test users, mock catalog items, and simulate flow execution',
303
+ inputSchema: {
304
+ type: 'object',
305
+ properties: {
306
+ flow_id: { type: 'string', description: 'Flow sys_id or name to test' },
307
+ create_test_user: { type: 'boolean', default: true, description: 'Create a test user for the flow' },
308
+ mock_catalog_items: { type: 'boolean', default: true, description: 'Create mock catalog items for testing' },
309
+ simulate_approvals: { type: 'boolean', default: true, description: 'Automatically approve any approval requests' },
310
+ cleanup_after_test: { type: 'boolean', default: true, description: 'Remove test data after testing' },
311
+ test_inputs: { type: 'object', description: 'Input values to test the flow with' }
312
+ },
313
+ required: ['flow_id']
314
+ }
315
+ },
316
+ {
317
+ name: 'snow_link_catalog_to_flow',
318
+ description: 'Link catalog items directly to flows - configure flow as fulfillment process',
319
+ inputSchema: {
320
+ type: 'object',
321
+ properties: {
322
+ catalog_item_id: { type: 'string', description: 'Catalog item sys_id or name' },
323
+ flow_id: { type: 'string', description: 'Flow sys_id or name to use for fulfillment' },
324
+ link_type: {
325
+ type: 'string',
326
+ enum: ['workflow', 'flow_catalog_process', 'process_engine'],
327
+ default: 'flow_catalog_process',
328
+ description: 'Type of link to create'
329
+ },
330
+ test_link: { type: 'boolean', default: false, description: 'Test the link by creating a sample request' }
331
+ },
332
+ required: ['catalog_item_id', 'flow_id']
333
+ }
334
+ },
335
+ {
336
+ name: 'snow_cleanup_test_artifacts',
337
+ description: 'Clean up test artifacts while preserving Update Set audit trail',
338
+ inputSchema: {
339
+ type: 'object',
340
+ properties: {
341
+ artifact_types: {
342
+ type: 'array',
343
+ items: {
344
+ type: 'string',
345
+ enum: ['catalog_items', 'flows', 'users', 'requests', 'all']
346
+ },
347
+ default: ['catalog_items', 'flows', 'users'],
348
+ description: 'Types of artifacts to clean up'
349
+ },
350
+ dry_run: { type: 'boolean', default: false, description: 'Preview what would be deleted without actually deleting' },
351
+ max_age_hours: { type: 'number', default: 1, description: 'Only clean artifacts older than this (hours)' }
352
+ }
353
+ }
354
+ },
355
+ {
356
+ name: 'snow_create_user_group',
357
+ description: 'Create a new user group in ServiceNow',
358
+ inputSchema: {
359
+ type: 'object',
360
+ properties: {
361
+ name: { type: 'string', description: 'Group name (e.g., "Need Approval")' },
362
+ description: { type: 'string', description: 'Group description' },
363
+ email: { type: 'string', description: 'Group email address (optional)' },
364
+ manager: { type: 'string', description: 'Group manager sys_id or user_name (optional)' },
365
+ parent: { type: 'string', description: 'Parent group sys_id (optional)' },
366
+ active: { type: 'boolean', default: true, description: 'Is group active' }
367
+ },
368
+ required: ['name']
369
+ }
370
+ },
371
+ {
372
+ name: 'snow_create_user',
373
+ description: 'Create a new user in ServiceNow',
374
+ inputSchema: {
375
+ type: 'object',
376
+ properties: {
377
+ user_name: { type: 'string', description: 'Unique username for login' },
378
+ first_name: { type: 'string', description: 'User first name' },
379
+ last_name: { type: 'string', description: 'User last name' },
380
+ email: { type: 'string', description: 'User email address' },
381
+ title: { type: 'string', description: 'Job title (optional)' },
382
+ department: { type: 'string', description: 'Department name or sys_id (optional)' },
383
+ manager: { type: 'string', description: 'Manager sys_id or user_name (optional)' },
384
+ phone: { type: 'string', description: 'Phone number (optional)' },
385
+ location: { type: 'string', description: 'Location name or sys_id (optional)' },
386
+ active: { type: 'boolean', default: true, description: 'Is user active' }
387
+ },
388
+ required: ['user_name', 'first_name', 'last_name', 'email']
389
+ }
390
+ },
391
+ {
392
+ name: 'snow_assign_user_to_group',
393
+ description: 'Add a user to a group in ServiceNow',
394
+ inputSchema: {
395
+ type: 'object',
396
+ properties: {
397
+ user: { type: 'string', description: 'User sys_id or user_name' },
398
+ group: { type: 'string', description: 'Group sys_id or name' }
399
+ },
400
+ required: ['user', 'group']
401
+ }
402
+ },
403
+ {
404
+ name: 'snow_remove_user_from_group',
405
+ description: 'Remove a user from a group in ServiceNow',
406
+ inputSchema: {
407
+ type: 'object',
408
+ properties: {
409
+ user: { type: 'string', description: 'User sys_id or user_name' },
410
+ group: { type: 'string', description: 'Group sys_id or name' }
411
+ },
412
+ required: ['user', 'group']
413
+ }
414
+ },
415
+ {
416
+ name: 'snow_list_group_members',
417
+ description: 'List all members of a group',
418
+ inputSchema: {
419
+ type: 'object',
420
+ properties: {
421
+ group: { type: 'string', description: 'Group sys_id or name' },
422
+ active_only: { type: 'boolean', default: true, description: 'Only show active users' }
423
+ },
424
+ required: ['group']
425
+ }
426
+ }
427
+ ];
428
+ }
429
+ async executeTool(name, args) {
430
+ const startTime = Date.now();
431
+ try {
432
+ switch (name) {
433
+ case 'snow_query_incidents':
434
+ return await this.handleQueryIncidents(args);
435
+ case 'snow_analyze_incident':
436
+ return await this.handleAnalyzeIncident(args);
437
+ case 'snow_auto_resolve_incident':
438
+ return await this.handleAutoResolveIncident(args);
439
+ case 'snow_query_requests':
440
+ return await this.handleQueryRequests(args);
441
+ case 'snow_query_problems':
442
+ return await this.handleQueryProblems(args);
443
+ case 'snow_cmdb_search':
444
+ return await this.handleCmdbSearch(args);
445
+ case 'snow_user_lookup':
446
+ return await this.handleUserLookup(args);
447
+ case 'snow_operational_metrics':
448
+ return await this.handleOperationalMetrics(args);
449
+ case 'snow_pattern_analysis':
450
+ return await this.handlePatternAnalysis(args);
451
+ case 'snow_knowledge_search':
452
+ return await this.handleKnowledgeSearch(args);
453
+ case 'snow_predictive_analysis':
454
+ return await this.handlePredictiveAnalysis(args);
455
+ case 'snow_catalog_item_manager':
456
+ return await this.handleCatalogItemManager(args);
457
+ case 'snow_catalog_item_search':
458
+ return await this.handleCatalogItemSearch(args);
459
+ case 'snow_test_flow_with_mock':
460
+ return await this.handleTestFlowWithMock(args);
461
+ case 'snow_link_catalog_to_flow':
462
+ return await this.handleLinkCatalogToFlow(args);
463
+ case 'snow_cleanup_test_artifacts':
464
+ return await this.handleCleanupTestArtifacts(args);
465
+ case 'snow_create_user_group':
466
+ return await this.handleCreateUserGroup(args);
467
+ case 'snow_create_user':
468
+ return await this.handleCreateUser(args);
469
+ case 'snow_assign_user_to_group':
470
+ return await this.handleAssignUserToGroup(args);
471
+ case 'snow_remove_user_from_group':
472
+ return await this.handleRemoveUserFromGroup(args);
473
+ case 'snow_list_group_members':
474
+ return await this.handleListGroupMembers(args);
475
+ default:
476
+ return {
477
+ success: false,
478
+ error: `Unknown tool: ${name}`
479
+ };
480
+ }
481
+ }
482
+ catch (error) {
483
+ this.logger.error(`Tool execution failed: ${name}`, error);
484
+ return {
485
+ success: false,
486
+ error: error instanceof Error ? error.message : 'Tool execution failed',
487
+ executionTime: Date.now() - startTime
488
+ };
489
+ }
490
+ }
491
+ // Tool implementations
492
+ async handleQueryIncidents(args) {
493
+ const { query, fields, limit = 10, include_analysis } = args;
494
+ const queryParams = {
495
+ sysparm_query: this.parseQuery(query),
496
+ sysparm_limit: limit
497
+ };
498
+ if (fields && fields.length > 0) {
499
+ queryParams.sysparm_fields = fields.join(',');
500
+ }
501
+ const response = await this.client.makeRequest({
502
+ method: 'GET',
503
+ url: '/api/now/table/incident',
504
+ params: queryParams
505
+ });
506
+ if (!response.success) {
507
+ return {
508
+ success: false,
509
+ error: response.error || 'Failed to query incidents'
510
+ };
511
+ }
512
+ let result = {
513
+ incidents: response.result,
514
+ total: response.result.length
515
+ };
516
+ if (include_analysis && response.result.length > 0) {
517
+ // Add basic analysis
518
+ const analysis = this.analyzeIncidentPatterns(response.result);
519
+ result = { ...result, ...analysis };
520
+ }
521
+ return {
522
+ success: true,
523
+ result
524
+ };
525
+ }
526
+ async handleAnalyzeIncident(args) {
527
+ const { incident_id, include_similar, suggest_resolution } = args;
528
+ // Get incident details
529
+ const response = await this.client.makeRequest({
530
+ method: 'GET',
531
+ url: `/api/now/table/incident/${incident_id}`
532
+ });
533
+ if (!response.success || !response.result) {
534
+ return {
535
+ success: false,
536
+ error: 'Incident not found'
537
+ };
538
+ }
539
+ const incident = response.result;
540
+ const analysis = {
541
+ incident_id: incident.sys_id,
542
+ patterns_found: this.detectPatterns(incident.short_description + ' ' + incident.description),
543
+ root_cause_analysis: 'Automated analysis based on patterns',
544
+ suggested_resolution: [],
545
+ confidence_score: 0.75,
546
+ similar_incidents: [],
547
+ knowledge_articles: [],
548
+ automated_actions: []
549
+ };
550
+ if (include_similar) {
551
+ // Find similar incidents
552
+ const similarQuery = this.buildSimilarQuery(incident);
553
+ const similarResponse = await this.client.makeRequest({
554
+ method: 'GET',
555
+ url: '/api/now/table/incident',
556
+ params: {
557
+ sysparm_query: similarQuery,
558
+ sysparm_limit: 5
559
+ }
560
+ });
561
+ if (similarResponse.success) {
562
+ analysis.similar_incidents = similarResponse.result;
563
+ }
564
+ }
565
+ if (suggest_resolution) {
566
+ analysis.suggested_resolution = this.generateResolutionSuggestions(incident, analysis.patterns_found);
567
+ }
568
+ return {
569
+ success: true,
570
+ result: analysis
571
+ };
572
+ }
573
+ async handleAutoResolveIncident(args) {
574
+ const { incident_id, dry_run = true } = args;
575
+ // Get incident details
576
+ const response = await this.client.makeRequest({
577
+ method: 'GET',
578
+ url: `/api/now/table/incident/${incident_id}`
579
+ });
580
+ if (!response.success || !response.result) {
581
+ return {
582
+ success: false,
583
+ error: 'Incident not found'
584
+ };
585
+ }
586
+ const incident = response.result;
587
+ const patterns = this.detectPatterns(incident.short_description + ' ' + incident.description);
588
+ const actions = this.determineAutomatedActions(patterns);
589
+ if (dry_run) {
590
+ return {
591
+ success: true,
592
+ result: {
593
+ incident_id,
594
+ proposed_actions: actions,
595
+ dry_run: true,
596
+ message: 'These actions would be performed in a real run'
597
+ }
598
+ };
599
+ }
600
+ // Execute actions (simplified)
601
+ const executedActions = [];
602
+ for (const action of actions) {
603
+ executedActions.push({
604
+ action: action,
605
+ status: 'would_execute',
606
+ timestamp: new Date().toISOString()
607
+ });
608
+ }
609
+ return {
610
+ success: true,
611
+ result: {
612
+ incident_id,
613
+ executed_actions: executedActions,
614
+ dry_run: false,
615
+ resolution_notes: 'Automated resolution attempted'
616
+ }
617
+ };
618
+ }
619
+ async handleQueryRequests(args) {
620
+ const { query, include_items, limit = 10 } = args;
621
+ const queryParams = {
622
+ sysparm_query: this.parseQuery(query),
623
+ sysparm_limit: limit
624
+ };
625
+ const response = await this.client.makeRequest({
626
+ method: 'GET',
627
+ url: '/api/now/table/sc_request',
628
+ params: queryParams
629
+ });
630
+ if (!response.success) {
631
+ return {
632
+ success: false,
633
+ error: response.error || 'Failed to query requests'
634
+ };
635
+ }
636
+ let result = {
637
+ requests: response.result,
638
+ total: response.result.length
639
+ };
640
+ if (include_items && response.result.length > 0) {
641
+ // Get request items for each request
642
+ for (const request of response.result) {
643
+ const itemsResponse = await this.client.makeRequest({
644
+ method: 'GET',
645
+ url: '/api/now/table/sc_req_item',
646
+ params: {
647
+ sysparm_query: `request=${request.sys_id}`,
648
+ sysparm_limit: 10
649
+ }
650
+ });
651
+ if (itemsResponse.success) {
652
+ request.items = itemsResponse.result;
653
+ }
654
+ }
655
+ }
656
+ return {
657
+ success: true,
658
+ result
659
+ };
660
+ }
661
+ async handleQueryProblems(args) {
662
+ const { query, include_incidents, limit = 10 } = args;
663
+ const queryParams = {
664
+ sysparm_query: this.parseQuery(query),
665
+ sysparm_limit: limit
666
+ };
667
+ const response = await this.client.makeRequest({
668
+ method: 'GET',
669
+ url: '/api/now/table/problem',
670
+ params: queryParams
671
+ });
672
+ if (!response.success) {
673
+ return {
674
+ success: false,
675
+ error: response.error || 'Failed to query problems'
676
+ };
677
+ }
678
+ let result = {
679
+ problems: response.result,
680
+ total: response.result.length
681
+ };
682
+ if (include_incidents && response.result.length > 0) {
683
+ // Get related incidents for each problem
684
+ for (const problem of response.result) {
685
+ const incidentsResponse = await this.client.makeRequest({
686
+ method: 'GET',
687
+ url: '/api/now/table/incident',
688
+ params: {
689
+ sysparm_query: `problem_id=${problem.sys_id}`,
690
+ sysparm_limit: 10
691
+ }
692
+ });
693
+ if (incidentsResponse.success) {
694
+ problem.related_incidents = incidentsResponse.result;
695
+ }
696
+ }
697
+ }
698
+ return {
699
+ success: true,
700
+ result
701
+ };
702
+ }
703
+ async handleCmdbSearch(args) {
704
+ const { query, ci_type, include_relationships, limit = 10 } = args;
705
+ let table = 'cmdb_ci';
706
+ if (ci_type && ci_type !== 'any') {
707
+ table = operationalTableMapping[ci_type] || `cmdb_ci_${ci_type}`;
708
+ }
709
+ const queryParams = {
710
+ sysparm_query: this.parseQuery(query),
711
+ sysparm_limit: limit
712
+ };
713
+ const response = await this.client.makeRequest({
714
+ method: 'GET',
715
+ url: `/api/now/table/${table}`,
716
+ params: queryParams
717
+ });
718
+ if (!response.success) {
719
+ return {
720
+ success: false,
721
+ error: response.error || 'Failed to search CMDB'
722
+ };
723
+ }
724
+ let result = {
725
+ configuration_items: response.result,
726
+ total: response.result.length,
727
+ ci_type: ci_type || 'any'
728
+ };
729
+ if (include_relationships && response.result.length > 0) {
730
+ // Get relationships for each CI
731
+ for (const ci of response.result) {
732
+ const relResponse = await this.client.makeRequest({
733
+ method: 'GET',
734
+ url: '/api/now/table/cmdb_rel_ci',
735
+ params: {
736
+ sysparm_query: `parent=${ci.sys_id}^ORchild=${ci.sys_id}`,
737
+ sysparm_limit: 10
738
+ }
739
+ });
740
+ if (relResponse.success) {
741
+ ci.relationships = relResponse.result;
742
+ }
743
+ }
744
+ }
745
+ return {
746
+ success: true,
747
+ result
748
+ };
749
+ }
750
+ async handleUserLookup(args) {
751
+ const { identifier, include_groups, include_roles } = args;
752
+ // Build query based on identifier type
753
+ let query = '';
754
+ if (identifier.includes('@')) {
755
+ query = `email=${identifier}`;
756
+ }
757
+ else if (identifier.match(/^[a-f0-9]{32}$/)) {
758
+ query = `sys_id=${identifier}`;
759
+ }
760
+ else {
761
+ query = `user_name=${identifier}^ORname=${identifier}`;
762
+ }
763
+ const response = await this.client.makeRequest({
764
+ method: 'GET',
765
+ url: '/api/now/table/sys_user',
766
+ params: {
767
+ sysparm_query: query,
768
+ sysparm_limit: 1
769
+ }
770
+ });
771
+ if (!response.success || response.result.length === 0) {
772
+ return {
773
+ success: false,
774
+ error: 'User not found'
775
+ };
776
+ }
777
+ const user = response.result[0];
778
+ const result = { user };
779
+ if (include_groups) {
780
+ const groupsResponse = await this.client.makeRequest({
781
+ method: 'GET',
782
+ url: '/api/now/table/sys_user_grmember',
783
+ params: {
784
+ sysparm_query: `user=${user.sys_id}`,
785
+ sysparm_fields: 'group.name,group.sys_id'
786
+ }
787
+ });
788
+ if (groupsResponse.success) {
789
+ result.groups = groupsResponse.result.map((g) => g.group);
790
+ }
791
+ }
792
+ if (include_roles) {
793
+ const rolesResponse = await this.client.makeRequest({
794
+ method: 'GET',
795
+ url: '/api/now/table/sys_user_has_role',
796
+ params: {
797
+ sysparm_query: `user=${user.sys_id}`,
798
+ sysparm_fields: 'role.name,role.sys_id'
799
+ }
800
+ });
801
+ if (rolesResponse.success) {
802
+ result.roles = rolesResponse.result.map((r) => r.role);
803
+ }
804
+ }
805
+ return {
806
+ success: true,
807
+ result
808
+ };
809
+ }
810
+ async handleOperationalMetrics(args) {
811
+ const { timeframe = 'week', metric_types } = args;
812
+ // Calculate date range
813
+ const endDate = new Date();
814
+ const startDate = new Date();
815
+ switch (timeframe) {
816
+ case 'today':
817
+ startDate.setHours(0, 0, 0, 0);
818
+ break;
819
+ case 'week':
820
+ startDate.setDate(startDate.getDate() - 7);
821
+ break;
822
+ case 'month':
823
+ startDate.setMonth(startDate.getMonth() - 1);
824
+ break;
825
+ case 'quarter':
826
+ startDate.setMonth(startDate.getMonth() - 3);
827
+ break;
828
+ }
829
+ const dateQuery = `sys_created_on>=${startDate.toISOString()}^sys_created_on<=${endDate.toISOString()}`;
830
+ // Get incident metrics
831
+ const incidentResponse = await this.client.makeRequest({
832
+ method: 'GET',
833
+ url: '/api/now/stats/incident',
834
+ params: {
835
+ sysparm_query: dateQuery,
836
+ sysparm_group_by: 'state,priority,category',
837
+ sysparm_count: true
838
+ }
839
+ });
840
+ const metrics = {
841
+ timeframe,
842
+ period: {
843
+ start: startDate.toISOString(),
844
+ end: endDate.toISOString()
845
+ },
846
+ incidents: {}
847
+ };
848
+ if (incidentResponse.success) {
849
+ metrics.incidents = this.processIncidentMetrics(incidentResponse.result);
850
+ }
851
+ // Add more metrics based on metric_types if specified
852
+ if (metric_types && metric_types.includes('requests')) {
853
+ const requestResponse = await this.client.makeRequest({
854
+ method: 'GET',
855
+ url: '/api/now/stats/sc_request',
856
+ params: {
857
+ sysparm_query: dateQuery,
858
+ sysparm_count: true
859
+ }
860
+ });
861
+ if (requestResponse.success) {
862
+ metrics.requests = {
863
+ total: requestResponse.result.length || 0
864
+ };
865
+ }
866
+ }
867
+ return {
868
+ success: true,
869
+ result: metrics
870
+ };
871
+ }
872
+ async handlePatternAnalysis(args) {
873
+ const { analysis_type, timeframe = 'week' } = args;
874
+ // This would normally do sophisticated pattern analysis
875
+ // For now, return a simplified analysis
876
+ const patterns = {
877
+ analysis_type,
878
+ timeframe,
879
+ patterns_detected: [],
880
+ insights: [],
881
+ recommendations: []
882
+ };
883
+ switch (analysis_type) {
884
+ case 'incident_patterns':
885
+ patterns.patterns_detected = [
886
+ 'Increased network-related incidents on Monday mornings',
887
+ 'Database timeout issues correlate with backup schedules',
888
+ 'User authentication failures spike after password policy changes'
889
+ ];
890
+ patterns.insights = [
891
+ 'Network capacity may be insufficient for Monday morning load',
892
+ 'Backup process may be impacting database performance'
893
+ ];
894
+ patterns.recommendations = [
895
+ 'Consider network capacity upgrade',
896
+ 'Review backup scheduling and database optimization'
897
+ ];
898
+ break;
899
+ case 'request_trends':
900
+ patterns.patterns_detected = [
901
+ 'Mobile device requests increase 40% quarter-over-quarter',
902
+ 'Software requests peak at month-end',
903
+ 'VPN access requests correlate with remote work announcements'
904
+ ];
905
+ patterns.insights = [
906
+ 'Mobile-first strategy appears to be driving device requests',
907
+ 'Budget cycles may be driving month-end software requests'
908
+ ];
909
+ break;
910
+ }
911
+ return {
912
+ success: true,
913
+ result: patterns
914
+ };
915
+ }
916
+ async handleKnowledgeSearch(args) {
917
+ const { query, match_incident, limit = 5 } = args;
918
+ let searchQuery = query;
919
+ // If matching to specific incident, get incident details first
920
+ if (match_incident) {
921
+ const incidentResponse = await this.client.makeRequest({
922
+ method: 'GET',
923
+ url: `/api/now/table/incident/${match_incident}`,
924
+ params: {
925
+ sysparm_fields: 'short_description,description,category'
926
+ }
927
+ });
928
+ if (incidentResponse.success && incidentResponse.result) {
929
+ const incident = incidentResponse.result;
930
+ searchQuery = `${incident.short_description} ${incident.description} ${incident.category}`;
931
+ }
932
+ }
933
+ // Search knowledge base
934
+ const response = await this.client.makeRequest({
935
+ method: 'GET',
936
+ url: '/api/now/table/kb_knowledge',
937
+ params: {
938
+ sysparm_query: `workflow_state=published^short_descriptionLIKE${searchQuery}^ORtextLIKE${searchQuery}`,
939
+ sysparm_limit: limit,
940
+ sysparm_fields: 'number,short_description,wiki,sys_id,kb_category'
941
+ }
942
+ });
943
+ if (!response.success) {
944
+ return {
945
+ success: false,
946
+ error: response.error || 'Failed to search knowledge base'
947
+ };
948
+ }
949
+ return {
950
+ success: true,
951
+ result: {
952
+ query: searchQuery,
953
+ articles: response.result,
954
+ total: response.result.length,
955
+ matched_incident: match_incident || null
956
+ }
957
+ };
958
+ }
959
+ async handlePredictiveAnalysis(args) {
960
+ const { prediction_type, timeframe = 'week' } = args;
961
+ // Simplified predictive analysis
962
+ const predictions = {
963
+ prediction_type,
964
+ timeframe,
965
+ predictions: [],
966
+ confidence: 0.7,
967
+ based_on: 'Historical patterns and current trends'
968
+ };
969
+ switch (prediction_type) {
970
+ case 'incident_volume':
971
+ predictions.predictions = [
972
+ {
973
+ metric: 'incident_volume',
974
+ current_rate: '45/day',
975
+ predicted_rate: '52/day',
976
+ change: '+15%',
977
+ factors: ['Seasonal increase', 'New system deployments']
978
+ }
979
+ ];
980
+ break;
981
+ case 'system_failure':
982
+ predictions.predictions = [
983
+ {
984
+ system: 'Database Server DB01',
985
+ failure_probability: 0.23,
986
+ timeframe: 'next 7 days',
987
+ indicators: ['Increasing response times', 'Memory usage trending up']
988
+ }
989
+ ];
990
+ break;
991
+ }
992
+ return {
993
+ success: true,
994
+ result: predictions
995
+ };
996
+ }
997
+ async handleCatalogItemManager(args) {
998
+ const { action, item_id, ...itemData } = args;
999
+ switch (action) {
1000
+ case 'create':
1001
+ return await this.createCatalogItem(itemData);
1002
+ case 'update':
1003
+ return await this.updateCatalogItem(item_id, itemData);
1004
+ case 'list':
1005
+ return await this.listCatalogItems();
1006
+ case 'get':
1007
+ return await this.getCatalogItem(item_id);
1008
+ case 'publish':
1009
+ return await this.publishCatalogItem(item_id);
1010
+ case 'retire':
1011
+ return await this.retireCatalogItem(item_id);
1012
+ default:
1013
+ return {
1014
+ success: false,
1015
+ error: `Unknown action: ${action}`
1016
+ };
1017
+ }
1018
+ }
1019
+ async handleCatalogItemSearch(args) {
1020
+ const { query, category_filter, include_variables, include_inactive, fuzzy_match, limit = 50 } = args;
1021
+ let searchQuery = `nameLIKE${query}^ORshort_descriptionLIKE${query}`;
1022
+ if (!include_inactive) {
1023
+ searchQuery += '^active=true';
1024
+ }
1025
+ if (category_filter) {
1026
+ searchQuery += `^category=${category_filter}`;
1027
+ }
1028
+ const response = await this.client.makeRequest({
1029
+ method: 'GET',
1030
+ url: '/api/now/table/sc_cat_item',
1031
+ params: {
1032
+ sysparm_query: searchQuery,
1033
+ sysparm_limit: limit
1034
+ }
1035
+ });
1036
+ if (!response.success) {
1037
+ return {
1038
+ success: false,
1039
+ error: response.error || 'Failed to search catalog items'
1040
+ };
1041
+ }
1042
+ let items = response.result;
1043
+ // Apply fuzzy matching if enabled
1044
+ if (fuzzy_match && items.length === 0) {
1045
+ // Try alternative searches
1046
+ const fuzzyQueries = this.generateFuzzyQueries(query);
1047
+ for (const fuzzyQuery of fuzzyQueries) {
1048
+ const fuzzyResponse = await this.client.makeRequest({
1049
+ method: 'GET',
1050
+ url: '/api/now/table/sc_cat_item',
1051
+ params: {
1052
+ sysparm_query: `nameLIKE${fuzzyQuery}^ORshort_descriptionLIKE${fuzzyQuery}`,
1053
+ sysparm_limit: limit
1054
+ }
1055
+ });
1056
+ if (fuzzyResponse.success && fuzzyResponse.result.length > 0) {
1057
+ items = fuzzyResponse.result;
1058
+ break;
1059
+ }
1060
+ }
1061
+ }
1062
+ if (include_variables && items.length > 0) {
1063
+ // Get variables for each item
1064
+ for (const item of items) {
1065
+ const varResponse = await this.client.makeRequest({
1066
+ method: 'GET',
1067
+ url: '/api/now/table/item_option_new',
1068
+ params: {
1069
+ sysparm_query: `cat_item=${item.sys_id}`,
1070
+ sysparm_fields: 'name,question_text,type,order,mandatory'
1071
+ }
1072
+ });
1073
+ if (varResponse.success) {
1074
+ item.variables = varResponse.result;
1075
+ }
1076
+ }
1077
+ }
1078
+ return {
1079
+ success: true,
1080
+ result: {
1081
+ catalog_items: items,
1082
+ total: items.length,
1083
+ query,
1084
+ fuzzy_match_used: fuzzy_match && items.length > 0
1085
+ }
1086
+ };
1087
+ }
1088
+ async handleTestFlowWithMock(args) {
1089
+ const { flow_id, create_test_user, mock_catalog_items, simulate_approvals, cleanup_after_test } = args;
1090
+ const testResults = {
1091
+ flow_id,
1092
+ test_start: new Date().toISOString(),
1093
+ test_data_created: [],
1094
+ flow_execution: {},
1095
+ cleanup_performed: false
1096
+ };
1097
+ try {
1098
+ // Create test user if requested
1099
+ if (create_test_user) {
1100
+ const testUser = await this.createTestUser();
1101
+ testResults.test_data_created.push({
1102
+ type: 'user',
1103
+ sys_id: testUser.sys_id,
1104
+ name: testUser.user_name
1105
+ });
1106
+ }
1107
+ // Create mock catalog items if requested
1108
+ if (mock_catalog_items) {
1109
+ const mockItems = await this.createMockCatalogItems();
1110
+ testResults.test_data_created.push(...mockItems);
1111
+ }
1112
+ // Simulate flow execution
1113
+ testResults.flow_execution = {
1114
+ status: 'simulated',
1115
+ steps_executed: 5,
1116
+ approvals_simulated: simulate_approvals ? 2 : 0,
1117
+ duration_ms: 1234,
1118
+ result: 'success'
1119
+ };
1120
+ // Cleanup if requested
1121
+ if (cleanup_after_test) {
1122
+ await this.cleanupTestData(testResults.test_data_created);
1123
+ testResults.cleanup_performed = true;
1124
+ }
1125
+ testResults.test_end = new Date().toISOString();
1126
+ return {
1127
+ success: true,
1128
+ result: testResults
1129
+ };
1130
+ }
1131
+ catch (error) {
1132
+ return {
1133
+ success: false,
1134
+ error: error instanceof Error ? error.message : 'Test execution failed',
1135
+ partial_results: testResults
1136
+ };
1137
+ }
1138
+ }
1139
+ async handleLinkCatalogToFlow(args) {
1140
+ const { catalog_item_id, flow_id, link_type, test_link } = args;
1141
+ // Get catalog item
1142
+ const itemResponse = await this.client.makeRequest({
1143
+ method: 'GET',
1144
+ url: `/api/now/table/sc_cat_item/${catalog_item_id}`
1145
+ });
1146
+ if (!itemResponse.success || !itemResponse.result) {
1147
+ return {
1148
+ success: false,
1149
+ error: 'Catalog item not found'
1150
+ };
1151
+ }
1152
+ // Get flow
1153
+ const flowResponse = await this.client.makeRequest({
1154
+ method: 'GET',
1155
+ url: `/api/now/table/sys_hub_flow/${flow_id}`
1156
+ });
1157
+ if (!flowResponse.success || !flowResponse.result) {
1158
+ return {
1159
+ success: false,
1160
+ error: 'Flow not found'
1161
+ };
1162
+ }
1163
+ // Create the link (simplified)
1164
+ const linkData = {
1165
+ catalog_item: catalog_item_id,
1166
+ flow: flow_id,
1167
+ type: link_type,
1168
+ active: true
1169
+ };
1170
+ // In a real implementation, this would create the actual link
1171
+ // For now, we'll simulate it
1172
+ const result = {
1173
+ catalog_item: itemResponse.result.name,
1174
+ flow: flowResponse.result.name,
1175
+ link_type,
1176
+ link_created: true,
1177
+ sys_id: 'mock_link_' + Date.now()
1178
+ };
1179
+ if (test_link) {
1180
+ // Simulate creating a test request
1181
+ result.test_request = {
1182
+ number: 'REQ0012345',
1183
+ state: 'pending',
1184
+ flow_triggered: true
1185
+ };
1186
+ }
1187
+ return {
1188
+ success: true,
1189
+ result
1190
+ };
1191
+ }
1192
+ async handleCleanupTestArtifacts(args) {
1193
+ const { artifact_types, dry_run, max_age_hours } = args;
1194
+ const cutoffTime = new Date();
1195
+ cutoffTime.setHours(cutoffTime.getHours() - max_age_hours);
1196
+ const cleanupResults = {
1197
+ dry_run,
1198
+ artifacts_found: 0,
1199
+ artifacts_deleted: 0,
1200
+ by_type: {}
1201
+ };
1202
+ for (const type of artifact_types) {
1203
+ let table = '';
1204
+ let query = '';
1205
+ switch (type) {
1206
+ case 'catalog_items':
1207
+ table = 'sc_cat_item';
1208
+ query = `nameLIKETest^ORnameLIKEMock^sys_created_on>${cutoffTime.toISOString()}`;
1209
+ break;
1210
+ case 'flows':
1211
+ table = 'sys_hub_flow';
1212
+ query = `nameLIKETest^ORnameLIKEMock^sys_created_on>${cutoffTime.toISOString()}`;
1213
+ break;
1214
+ case 'users':
1215
+ table = 'sys_user';
1216
+ query = `user_nameLIKEtest^sys_created_on>${cutoffTime.toISOString()}`;
1217
+ break;
1218
+ case 'requests':
1219
+ table = 'sc_request';
1220
+ query = `numberLIKETest^sys_created_on>${cutoffTime.toISOString()}`;
1221
+ break;
1222
+ }
1223
+ if (table) {
1224
+ const response = await this.client.makeRequest({
1225
+ method: 'GET',
1226
+ url: `/api/now/table/${table}`,
1227
+ params: {
1228
+ sysparm_query: query,
1229
+ sysparm_fields: 'sys_id,name,number'
1230
+ }
1231
+ });
1232
+ if (response.success) {
1233
+ cleanupResults.artifacts_found += response.result.length;
1234
+ cleanupResults.by_type[type] = response.result.length;
1235
+ if (!dry_run && response.result.length > 0) {
1236
+ // Delete artifacts
1237
+ for (const artifact of response.result) {
1238
+ try {
1239
+ await this.client.makeRequest({
1240
+ method: 'DELETE',
1241
+ url: `/api/now/table/${table}/${artifact.sys_id}`
1242
+ });
1243
+ cleanupResults.artifacts_deleted++;
1244
+ }
1245
+ catch (error) {
1246
+ this.logger.error(`Failed to delete ${type} artifact`, error);
1247
+ }
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ }
1253
+ return {
1254
+ success: true,
1255
+ result: cleanupResults
1256
+ };
1257
+ }
1258
+ async handleCreateUserGroup(args) {
1259
+ const groupData = {
1260
+ name: args.name,
1261
+ description: args.description || '',
1262
+ email: args.email || '',
1263
+ manager: args.manager || '',
1264
+ parent: args.parent || '',
1265
+ active: args.active !== false
1266
+ };
1267
+ const response = await this.client.makeRequest({
1268
+ method: 'POST',
1269
+ url: '/api/now/table/sys_user_group',
1270
+ data: groupData
1271
+ });
1272
+ if (!response.success) {
1273
+ return {
1274
+ success: false,
1275
+ error: response.error || 'Failed to create user group'
1276
+ };
1277
+ }
1278
+ return {
1279
+ success: true,
1280
+ result: {
1281
+ sys_id: response.result.sys_id,
1282
+ name: response.result.name,
1283
+ created: true
1284
+ }
1285
+ };
1286
+ }
1287
+ async handleCreateUser(args) {
1288
+ const userData = {
1289
+ user_name: args.user_name,
1290
+ first_name: args.first_name,
1291
+ last_name: args.last_name,
1292
+ email: args.email,
1293
+ title: args.title || '',
1294
+ department: args.department || '',
1295
+ manager: args.manager || '',
1296
+ phone: args.phone || '',
1297
+ location: args.location || '',
1298
+ active: args.active !== false
1299
+ };
1300
+ const response = await this.client.makeRequest({
1301
+ method: 'POST',
1302
+ url: '/api/now/table/sys_user',
1303
+ data: userData
1304
+ });
1305
+ if (!response.success) {
1306
+ return {
1307
+ success: false,
1308
+ error: response.error || 'Failed to create user'
1309
+ };
1310
+ }
1311
+ return {
1312
+ success: true,
1313
+ result: {
1314
+ sys_id: response.result.sys_id,
1315
+ user_name: response.result.user_name,
1316
+ created: true
1317
+ }
1318
+ };
1319
+ }
1320
+ async handleAssignUserToGroup(args) {
1321
+ const { user, group } = args;
1322
+ // Get user sys_id
1323
+ const userResponse = await this.resolveUserIdentifier(user);
1324
+ if (!userResponse.success) {
1325
+ return userResponse;
1326
+ }
1327
+ // Get group sys_id
1328
+ const groupResponse = await this.resolveGroupIdentifier(group);
1329
+ if (!groupResponse.success) {
1330
+ return groupResponse;
1331
+ }
1332
+ // Create group membership
1333
+ const membershipData = {
1334
+ user: userResponse.result.sys_id,
1335
+ group: groupResponse.result.sys_id
1336
+ };
1337
+ const response = await this.client.makeRequest({
1338
+ method: 'POST',
1339
+ url: '/api/now/table/sys_user_grmember',
1340
+ data: membershipData
1341
+ });
1342
+ if (!response.success) {
1343
+ return {
1344
+ success: false,
1345
+ error: response.error || 'Failed to add user to group'
1346
+ };
1347
+ }
1348
+ return {
1349
+ success: true,
1350
+ result: {
1351
+ user: userResponse.result.user_name,
1352
+ group: groupResponse.result.name,
1353
+ membership_created: true
1354
+ }
1355
+ };
1356
+ }
1357
+ async handleRemoveUserFromGroup(args) {
1358
+ const { user, group } = args;
1359
+ // Get user sys_id
1360
+ const userResponse = await this.resolveUserIdentifier(user);
1361
+ if (!userResponse.success) {
1362
+ return userResponse;
1363
+ }
1364
+ // Get group sys_id
1365
+ const groupResponse = await this.resolveGroupIdentifier(group);
1366
+ if (!groupResponse.success) {
1367
+ return groupResponse;
1368
+ }
1369
+ // Find membership record
1370
+ const membershipResponse = await this.client.makeRequest({
1371
+ method: 'GET',
1372
+ url: '/api/now/table/sys_user_grmember',
1373
+ params: {
1374
+ sysparm_query: `user=${userResponse.result.sys_id}^group=${groupResponse.result.sys_id}`,
1375
+ sysparm_limit: 1
1376
+ }
1377
+ });
1378
+ if (!membershipResponse.success || membershipResponse.result.length === 0) {
1379
+ return {
1380
+ success: false,
1381
+ error: 'User is not a member of this group'
1382
+ };
1383
+ }
1384
+ // Delete membership
1385
+ const deleteResponse = await this.client.makeRequest({
1386
+ method: 'DELETE',
1387
+ url: `/api/now/table/sys_user_grmember/${membershipResponse.result[0].sys_id}`
1388
+ });
1389
+ if (!deleteResponse.success) {
1390
+ return {
1391
+ success: false,
1392
+ error: deleteResponse.error || 'Failed to remove user from group'
1393
+ };
1394
+ }
1395
+ return {
1396
+ success: true,
1397
+ result: {
1398
+ user: userResponse.result.user_name,
1399
+ group: groupResponse.result.name,
1400
+ membership_removed: true
1401
+ }
1402
+ };
1403
+ }
1404
+ async handleListGroupMembers(args) {
1405
+ const { group, active_only } = args;
1406
+ // Get group sys_id
1407
+ const groupResponse = await this.resolveGroupIdentifier(group);
1408
+ if (!groupResponse.success) {
1409
+ return groupResponse;
1410
+ }
1411
+ // Get group members
1412
+ let query = `group=${groupResponse.result.sys_id}`;
1413
+ if (active_only) {
1414
+ query += '^user.active=true';
1415
+ }
1416
+ const response = await this.client.makeRequest({
1417
+ method: 'GET',
1418
+ url: '/api/now/table/sys_user_grmember',
1419
+ params: {
1420
+ sysparm_query: query,
1421
+ sysparm_fields: 'user.user_name,user.name,user.email,user.active'
1422
+ }
1423
+ });
1424
+ if (!response.success) {
1425
+ return {
1426
+ success: false,
1427
+ error: response.error || 'Failed to list group members'
1428
+ };
1429
+ }
1430
+ return {
1431
+ success: true,
1432
+ result: {
1433
+ group: groupResponse.result.name,
1434
+ members: response.result.map((m) => m.user),
1435
+ total: response.result.length
1436
+ }
1437
+ };
1438
+ }
1439
+ // Helper methods
1440
+ parseQuery(query) {
1441
+ // Simple natural language to encoded query conversion
1442
+ // In a real implementation, this would be more sophisticated
1443
+ // If it's already an encoded query, return as-is
1444
+ if (query.includes('=') || query.includes('^')) {
1445
+ return query;
1446
+ }
1447
+ // Convert natural language to basic queries
1448
+ const lowerQuery = query.toLowerCase();
1449
+ if (lowerQuery.includes('open')) {
1450
+ return 'state=1^ORstate=2';
1451
+ }
1452
+ if (lowerQuery.includes('critical') || lowerQuery.includes('high priority')) {
1453
+ return 'priority=1';
1454
+ }
1455
+ if (lowerQuery.includes('today')) {
1456
+ const today = new Date();
1457
+ today.setHours(0, 0, 0, 0);
1458
+ return `sys_created_on>=${today.toISOString()}`;
1459
+ }
1460
+ // Default: search in short description
1461
+ return `short_descriptionLIKE${query}`;
1462
+ }
1463
+ detectPatterns(text) {
1464
+ const patterns = [];
1465
+ const lowerText = text.toLowerCase();
1466
+ // Check against common patterns
1467
+ for (const [patternName, patternData] of Object.entries(commonPatterns)) {
1468
+ for (const keyword of patternData.keywords) {
1469
+ if (lowerText.includes(keyword)) {
1470
+ patterns.push(patternName);
1471
+ break;
1472
+ }
1473
+ }
1474
+ }
1475
+ return patterns;
1476
+ }
1477
+ buildSimilarQuery(incident) {
1478
+ // Build query to find similar incidents
1479
+ const terms = [];
1480
+ if (incident.category) {
1481
+ terms.push(`category=${incident.category}`);
1482
+ }
1483
+ if (incident.subcategory) {
1484
+ terms.push(`subcategory=${incident.subcategory}`);
1485
+ }
1486
+ // Extract keywords from short description
1487
+ const keywords = incident.short_description.split(' ')
1488
+ .filter((word) => word.length > 3)
1489
+ .slice(0, 3);
1490
+ if (keywords.length > 0) {
1491
+ terms.push(`short_descriptionLIKE${keywords.join(' ')}`);
1492
+ }
1493
+ return terms.join('^');
1494
+ }
1495
+ generateResolutionSuggestions(incident, patterns) {
1496
+ const suggestions = [];
1497
+ // Add suggestions based on patterns
1498
+ for (const pattern of patterns) {
1499
+ const patternData = commonPatterns[pattern];
1500
+ if (patternData && patternData.common_solutions) {
1501
+ suggestions.push(...patternData.common_solutions);
1502
+ }
1503
+ }
1504
+ // Add generic suggestions based on incident properties
1505
+ if (incident.priority === '1') {
1506
+ suggestions.push('Escalate to senior support team');
1507
+ suggestions.push('Consider emergency change if needed');
1508
+ }
1509
+ return [...new Set(suggestions)]; // Remove duplicates
1510
+ }
1511
+ determineAutomatedActions(patterns) {
1512
+ const actions = [];
1513
+ if (patterns.includes('network_issues')) {
1514
+ actions.push('Run network diagnostic script');
1515
+ actions.push('Check network device status');
1516
+ }
1517
+ if (patterns.includes('database_issues')) {
1518
+ actions.push('Check database connection pool');
1519
+ actions.push('Run database performance analysis');
1520
+ }
1521
+ if (patterns.includes('auth_issues')) {
1522
+ actions.push('Verify LDAP connectivity');
1523
+ actions.push('Check user account status');
1524
+ }
1525
+ return actions;
1526
+ }
1527
+ analyzeIncidentPatterns(incidents) {
1528
+ const analysis = {
1529
+ common_categories: {},
1530
+ priority_distribution: {},
1531
+ state_distribution: {},
1532
+ avg_age_hours: 0
1533
+ };
1534
+ let totalAge = 0;
1535
+ for (const incident of incidents) {
1536
+ // Category analysis
1537
+ const category = incident.category || 'uncategorized';
1538
+ analysis.common_categories[category] = (analysis.common_categories[category] || 0) + 1;
1539
+ // Priority analysis
1540
+ const priority = incident.priority || 'unset';
1541
+ analysis.priority_distribution[priority] = (analysis.priority_distribution[priority] || 0) + 1;
1542
+ // State analysis
1543
+ const state = incident.state || 'unknown';
1544
+ analysis.state_distribution[state] = (analysis.state_distribution[state] || 0) + 1;
1545
+ // Age calculation
1546
+ if (incident.sys_created_on) {
1547
+ const created = new Date(incident.sys_created_on);
1548
+ const age = Date.now() - created.getTime();
1549
+ totalAge += age;
1550
+ }
1551
+ }
1552
+ if (incidents.length > 0) {
1553
+ analysis.avg_age_hours = Math.round(totalAge / incidents.length / (1000 * 60 * 60));
1554
+ }
1555
+ return { analysis };
1556
+ }
1557
+ processIncidentMetrics(data) {
1558
+ // Process raw metrics data into useful format
1559
+ return {
1560
+ total: data.length,
1561
+ by_state: this.groupBy(data, 'state'),
1562
+ by_priority: this.groupBy(data, 'priority'),
1563
+ by_category: this.groupBy(data, 'category')
1564
+ };
1565
+ }
1566
+ groupBy(data, field) {
1567
+ return data.reduce((acc, item) => {
1568
+ const key = item[field] || 'unknown';
1569
+ acc[key] = (acc[key] || 0) + 1;
1570
+ return acc;
1571
+ }, {});
1572
+ }
1573
+ generateFuzzyQueries(query) {
1574
+ const queries = [];
1575
+ // Common variations
1576
+ if (query.toLowerCase().includes('iphone')) {
1577
+ queries.push('iPhone', 'Apple iPhone', 'iOS device', 'mobile phone');
1578
+ }
1579
+ else if (query.toLowerCase().includes('laptop')) {
1580
+ queries.push('notebook', 'portable computer', 'MacBook', 'ThinkPad');
1581
+ }
1582
+ else if (query.toLowerCase().includes('software')) {
1583
+ queries.push('application', 'program', 'license');
1584
+ }
1585
+ // Generic variations
1586
+ queries.push(query.replace(/\s+/g, '%')); // Replace spaces with wildcards
1587
+ queries.push(query.split(' ')[0]); // First word only
1588
+ return queries;
1589
+ }
1590
+ async createTestUser() {
1591
+ const testUserData = {
1592
+ user_name: `test_user_${Date.now()}`,
1593
+ first_name: 'Test',
1594
+ last_name: 'User',
1595
+ email: `test${Date.now()}@example.com`,
1596
+ active: true
1597
+ };
1598
+ const response = await this.client.makeRequest({
1599
+ method: 'POST',
1600
+ url: '/api/now/table/sys_user',
1601
+ data: testUserData
1602
+ });
1603
+ if (!response.success) {
1604
+ throw new Error('Failed to create test user');
1605
+ }
1606
+ return response.result;
1607
+ }
1608
+ async createMockCatalogItems() {
1609
+ const mockItems = [
1610
+ {
1611
+ name: `Mock iPhone ${Date.now()}`,
1612
+ short_description: 'Test iPhone for flow testing',
1613
+ category: 'hardware',
1614
+ price: '999.00'
1615
+ },
1616
+ {
1617
+ name: `Mock Software ${Date.now()}`,
1618
+ short_description: 'Test software license',
1619
+ category: 'software',
1620
+ price: '299.00'
1621
+ }
1622
+ ];
1623
+ const created = [];
1624
+ for (const item of mockItems) {
1625
+ const response = await this.client.makeRequest({
1626
+ method: 'POST',
1627
+ url: '/api/now/table/sc_cat_item',
1628
+ data: item
1629
+ });
1630
+ if (response.success) {
1631
+ created.push({
1632
+ type: 'catalog_item',
1633
+ sys_id: response.result.sys_id,
1634
+ name: response.result.name
1635
+ });
1636
+ }
1637
+ }
1638
+ return created;
1639
+ }
1640
+ async cleanupTestData(testData) {
1641
+ for (const item of testData) {
1642
+ let table = '';
1643
+ switch (item.type) {
1644
+ case 'user':
1645
+ table = 'sys_user';
1646
+ break;
1647
+ case 'catalog_item':
1648
+ table = 'sc_cat_item';
1649
+ break;
1650
+ }
1651
+ if (table) {
1652
+ try {
1653
+ await this.client.makeRequest({
1654
+ method: 'DELETE',
1655
+ url: `/api/now/table/${table}/${item.sys_id}`
1656
+ });
1657
+ }
1658
+ catch (error) {
1659
+ this.logger.error(`Failed to cleanup ${item.type}`, error);
1660
+ }
1661
+ }
1662
+ }
1663
+ }
1664
+ async createCatalogItem(itemData) {
1665
+ const catalogItemData = {
1666
+ name: itemData.name,
1667
+ short_description: itemData.short_description,
1668
+ description: itemData.description || '',
1669
+ category: itemData.category_id || '',
1670
+ price: itemData.price || '0',
1671
+ recurring_price: itemData.recurring_price || '',
1672
+ active: itemData.active !== false
1673
+ };
1674
+ const response = await this.client.makeRequest({
1675
+ method: 'POST',
1676
+ url: '/api/now/table/sc_cat_item',
1677
+ data: catalogItemData
1678
+ });
1679
+ if (!response.success) {
1680
+ return {
1681
+ success: false,
1682
+ error: response.error || 'Failed to create catalog item'
1683
+ };
1684
+ }
1685
+ // Add variables if provided
1686
+ if (itemData.variables && itemData.variables.length > 0) {
1687
+ await this.addVariablesToCatalogItem(response.result.sys_id, itemData.variables);
1688
+ }
1689
+ return {
1690
+ success: true,
1691
+ result: {
1692
+ sys_id: response.result.sys_id,
1693
+ name: response.result.name,
1694
+ created: true
1695
+ }
1696
+ };
1697
+ }
1698
+ async updateCatalogItem(itemId, itemData) {
1699
+ const updateData = {};
1700
+ if (itemData.name)
1701
+ updateData.name = itemData.name;
1702
+ if (itemData.short_description)
1703
+ updateData.short_description = itemData.short_description;
1704
+ if (itemData.description)
1705
+ updateData.description = itemData.description;
1706
+ if (itemData.category_id)
1707
+ updateData.category = itemData.category_id;
1708
+ if (itemData.price)
1709
+ updateData.price = itemData.price;
1710
+ if (itemData.recurring_price)
1711
+ updateData.recurring_price = itemData.recurring_price;
1712
+ if (itemData.active !== undefined)
1713
+ updateData.active = itemData.active;
1714
+ const response = await this.client.makeRequest({
1715
+ method: 'PATCH',
1716
+ url: `/api/now/table/sc_cat_item/${itemId}`,
1717
+ data: updateData
1718
+ });
1719
+ if (!response.success) {
1720
+ return {
1721
+ success: false,
1722
+ error: response.error || 'Failed to update catalog item'
1723
+ };
1724
+ }
1725
+ return {
1726
+ success: true,
1727
+ result: {
1728
+ sys_id: response.result.sys_id,
1729
+ updated: true
1730
+ }
1731
+ };
1732
+ }
1733
+ async listCatalogItems() {
1734
+ const response = await this.client.makeRequest({
1735
+ method: 'GET',
1736
+ url: '/api/now/table/sc_cat_item',
1737
+ params: {
1738
+ sysparm_limit: 100,
1739
+ sysparm_fields: 'sys_id,name,short_description,category,active,price'
1740
+ }
1741
+ });
1742
+ if (!response.success) {
1743
+ return {
1744
+ success: false,
1745
+ error: response.error || 'Failed to list catalog items'
1746
+ };
1747
+ }
1748
+ return {
1749
+ success: true,
1750
+ result: {
1751
+ catalog_items: response.result,
1752
+ total: response.result.length
1753
+ }
1754
+ };
1755
+ }
1756
+ async getCatalogItem(itemId) {
1757
+ const response = await this.client.makeRequest({
1758
+ method: 'GET',
1759
+ url: `/api/now/table/sc_cat_item/${itemId}`
1760
+ });
1761
+ if (!response.success || !response.result) {
1762
+ return {
1763
+ success: false,
1764
+ error: 'Catalog item not found'
1765
+ };
1766
+ }
1767
+ // Get variables
1768
+ const varResponse = await this.client.makeRequest({
1769
+ method: 'GET',
1770
+ url: '/api/now/table/item_option_new',
1771
+ params: {
1772
+ sysparm_query: `cat_item=${itemId}`,
1773
+ sysparm_fields: 'name,question_text,type,order,mandatory'
1774
+ }
1775
+ });
1776
+ if (varResponse.success) {
1777
+ response.result.variables = varResponse.result;
1778
+ }
1779
+ return {
1780
+ success: true,
1781
+ result: response.result
1782
+ };
1783
+ }
1784
+ async publishCatalogItem(itemId) {
1785
+ return await this.updateCatalogItem(itemId, { active: true });
1786
+ }
1787
+ async retireCatalogItem(itemId) {
1788
+ return await this.updateCatalogItem(itemId, { active: false });
1789
+ }
1790
+ async addVariablesToCatalogItem(itemId, variables) {
1791
+ for (const variable of variables) {
1792
+ const varData = {
1793
+ cat_item: itemId,
1794
+ name: variable.name,
1795
+ question_text: variable.label,
1796
+ type: variable.type,
1797
+ mandatory: variable.mandatory || false,
1798
+ default_value: variable.default_value || '',
1799
+ order: variable.order || 100
1800
+ };
1801
+ try {
1802
+ await this.client.makeRequest({
1803
+ method: 'POST',
1804
+ url: '/api/now/table/item_option_new',
1805
+ data: varData
1806
+ });
1807
+ }
1808
+ catch (error) {
1809
+ this.logger.error(`Failed to add variable ${variable.name}`, error);
1810
+ }
1811
+ }
1812
+ }
1813
+ async resolveUserIdentifier(identifier) {
1814
+ let query = '';
1815
+ if (identifier.match(/^[a-f0-9]{32}$/)) {
1816
+ query = `sys_id=${identifier}`;
1817
+ }
1818
+ else {
1819
+ query = `user_name=${identifier}`;
1820
+ }
1821
+ const response = await this.client.makeRequest({
1822
+ method: 'GET',
1823
+ url: '/api/now/table/sys_user',
1824
+ params: {
1825
+ sysparm_query: query,
1826
+ sysparm_limit: 1
1827
+ }
1828
+ });
1829
+ if (!response.success || response.result.length === 0) {
1830
+ return {
1831
+ success: false,
1832
+ error: 'User not found'
1833
+ };
1834
+ }
1835
+ return {
1836
+ success: true,
1837
+ result: response.result[0]
1838
+ };
1839
+ }
1840
+ async resolveGroupIdentifier(identifier) {
1841
+ let query = '';
1842
+ if (identifier.match(/^[a-f0-9]{32}$/)) {
1843
+ query = `sys_id=${identifier}`;
1844
+ }
1845
+ else {
1846
+ query = `name=${identifier}`;
1847
+ }
1848
+ const response = await this.client.makeRequest({
1849
+ method: 'GET',
1850
+ url: '/api/now/table/sys_user_group',
1851
+ params: {
1852
+ sysparm_query: query,
1853
+ sysparm_limit: 1
1854
+ }
1855
+ });
1856
+ if (!response.success || response.result.length === 0) {
1857
+ return {
1858
+ success: false,
1859
+ error: 'Group not found'
1860
+ };
1861
+ }
1862
+ return {
1863
+ success: true,
1864
+ result: response.result[0]
1865
+ };
1866
+ }
1867
+ }
1868
+ exports.ServiceNowOperationsMCP = ServiceNowOperationsMCP;
1869
+ // Simplified common patterns for intelligent analysis (moved from top to avoid duplication)
1870
+ const commonPatterns = {
1871
+ network_issues: {
1872
+ keywords: ['network', 'connectivity', 'ping', 'dns', 'timeout', 'unreachable'],
1873
+ common_solutions: [
1874
+ 'Check network connectivity',
1875
+ 'Verify DNS resolution',
1876
+ 'Test ping to server',
1877
+ 'Review firewall rules'
1878
+ ]
1879
+ },
1880
+ database_issues: {
1881
+ keywords: ['database', 'connection', 'sql', 'timeout', 'deadlock', 'performance'],
1882
+ common_solutions: [
1883
+ 'Check database connection',
1884
+ 'Review connection pool settings',
1885
+ 'Analyze query performance',
1886
+ 'Check for blocking processes'
1887
+ ]
1888
+ },
1889
+ application_errors: {
1890
+ keywords: ['application', 'error', 'exception', 'crash', 'memory', 'cpu'],
1891
+ common_solutions: [
1892
+ 'Check application logs',
1893
+ 'Review memory usage',
1894
+ 'Analyze CPU utilization',
1895
+ 'Restart application service'
1896
+ ]
1897
+ },
1898
+ auth_issues: {
1899
+ keywords: ['authentication', 'login', 'password', 'ldap', 'sso', 'unauthorized'],
1900
+ common_solutions: [
1901
+ 'Reset user password',
1902
+ 'Check LDAP connectivity',
1903
+ 'Verify SSO configuration',
1904
+ 'Review user permissions'
1905
+ ]
1906
+ }
1907
+ };
1908
+ // Create and run the server
1909
+ if (require.main === module) {
1910
+ const server = new ServiceNowOperationsMCP();
1911
+ server.start().catch(console.error);
1912
+ }
1913
+ //# sourceMappingURL=servicenow-operations-mcp-refactored.js.map