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