snow-flow 3.3.0 ā 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dynamic-version.js +1 -1
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp-enhanced.js +816 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp-enhanced.js +1112 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp-enhanced.js +860 -0
- package/dist/mcp/servicenow-knowledge-catalog-mcp-enhanced.js +503 -1
- package/dist/mcp/shared/enhanced-base-mcp-server.d.ts +8 -0
- package/dist/mcp/shared/enhanced-base-mcp-server.js +24 -0
- package/dist/mcp/shared/mcp-logger.js +2 -1
- package/package.json +2 -2
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ServiceNow Change Management, Virtual Agent & Performance Analytics MCP Server - ENHANCED VERSION
|
|
5
|
+
* With logging, token tracking, and progress indicators
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
9
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
10
|
+
const enhanced_base_mcp_server_js_1 = require("./shared/enhanced-base-mcp-server.js");
|
|
11
|
+
const mcp_config_manager_js_1 = require("../utils/mcp-config-manager.js");
|
|
12
|
+
class ServiceNowChangeVirtualAgentPAMCPEnhanced extends enhanced_base_mcp_server_js_1.EnhancedBaseMCPServer {
|
|
13
|
+
constructor() {
|
|
14
|
+
super('servicenow-change-virtualagent-pa-enhanced', '2.0.0');
|
|
15
|
+
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
16
|
+
this.setupHandlers();
|
|
17
|
+
}
|
|
18
|
+
setupHandlers() {
|
|
19
|
+
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
20
|
+
tools: [
|
|
21
|
+
// Change Management Tools
|
|
22
|
+
{
|
|
23
|
+
name: 'snow_create_change_request',
|
|
24
|
+
description: 'Creates change request in ServiceNow using change_request table.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
short_description: { type: 'string', description: 'Change summary' },
|
|
29
|
+
description: { type: 'string', description: 'Detailed description' },
|
|
30
|
+
type: { type: 'string', description: 'normal, standard, emergency' },
|
|
31
|
+
risk: { type: 'string', description: 'high, moderate, low' },
|
|
32
|
+
impact: { type: 'string', description: '1-critical, 2-high, 3-moderate, 4-low' },
|
|
33
|
+
implementation_plan: { type: 'string', description: 'Implementation steps' },
|
|
34
|
+
backout_plan: { type: 'string', description: 'Rollback steps' },
|
|
35
|
+
test_plan: { type: 'string', description: 'Testing steps' },
|
|
36
|
+
justification: { type: 'string', description: 'Business justification' },
|
|
37
|
+
start_date: { type: 'string', description: 'Planned start (YYYY-MM-DD HH:MM:SS)' },
|
|
38
|
+
end_date: { type: 'string', description: 'Planned end (YYYY-MM-DD HH:MM:SS)' }
|
|
39
|
+
},
|
|
40
|
+
required: ['short_description', 'type']
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'snow_create_change_task',
|
|
45
|
+
description: 'Creates change task using change_task table.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
change_request: { type: 'string', description: 'Parent change sys_id' },
|
|
50
|
+
short_description: { type: 'string', description: 'Task description' },
|
|
51
|
+
assignment_group: { type: 'string', description: 'Group sys_id' },
|
|
52
|
+
assigned_to: { type: 'string', description: 'User sys_id' },
|
|
53
|
+
order: { type: 'number', description: 'Task order' }
|
|
54
|
+
},
|
|
55
|
+
required: ['change_request', 'short_description']
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'snow_get_change_request',
|
|
60
|
+
description: 'Gets change request details from change_request table.',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
sys_id: { type: 'string', description: 'Change request sys_id' },
|
|
65
|
+
include_tasks: { type: 'boolean', default: false }
|
|
66
|
+
},
|
|
67
|
+
required: ['sys_id']
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'snow_update_change_state',
|
|
72
|
+
description: 'Updates change request state in change_request table.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
sys_id: { type: 'string', description: 'Change request sys_id' },
|
|
77
|
+
state: { type: 'string', description: 'new, assess, authorize, scheduled, implement, review, closed' },
|
|
78
|
+
close_notes: { type: 'string', description: 'Closure notes' }
|
|
79
|
+
},
|
|
80
|
+
required: ['sys_id', 'state']
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'snow_schedule_cab_meeting',
|
|
85
|
+
description: 'Schedules CAB meeting using cab_meeting and cab_agenda_item tables.',
|
|
86
|
+
inputSchema: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
properties: {
|
|
89
|
+
meeting_date: { type: 'string', description: 'Meeting date/time' },
|
|
90
|
+
location: { type: 'string', description: 'Meeting location' },
|
|
91
|
+
change_requests: { type: 'array', items: { type: 'string' }, description: 'Change sys_ids' }
|
|
92
|
+
},
|
|
93
|
+
required: ['meeting_date']
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'snow_search_change_requests',
|
|
98
|
+
description: 'Searches change requests in change_request table.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
query: { type: 'string', description: 'Search query' },
|
|
103
|
+
state: { type: 'string', description: 'Filter by state' },
|
|
104
|
+
type: { type: 'string', description: 'Filter by type' },
|
|
105
|
+
risk: { type: 'string', description: 'Filter by risk' },
|
|
106
|
+
limit: { type: 'number', default: 10 }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
// Virtual Agent Tools
|
|
111
|
+
{
|
|
112
|
+
name: 'snow_create_va_topic',
|
|
113
|
+
description: 'Creates virtual agent topic using sys_cs_topic table.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
name: { type: 'string', description: 'Topic name' },
|
|
118
|
+
description: { type: 'string', description: 'Topic description' },
|
|
119
|
+
trigger_phrases: { type: 'array', items: { type: 'string' } },
|
|
120
|
+
category: { type: 'string', description: 'Topic category' },
|
|
121
|
+
active: { type: 'boolean', default: true }
|
|
122
|
+
},
|
|
123
|
+
required: ['name', 'trigger_phrases']
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'snow_create_va_topic_block',
|
|
128
|
+
description: 'Creates conversation blocks using sys_cs_topic_block table.',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {
|
|
132
|
+
topic: { type: 'string', description: 'Topic sys_id' },
|
|
133
|
+
type: { type: 'string', description: 'Block type: text, question, action' },
|
|
134
|
+
message: { type: 'string', description: 'Block message' },
|
|
135
|
+
order: { type: 'number', description: 'Block order' },
|
|
136
|
+
options: { type: 'array', items: { type: 'object' } }
|
|
137
|
+
},
|
|
138
|
+
required: ['topic', 'type', 'message']
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'snow_get_va_conversation',
|
|
143
|
+
description: 'Gets conversation history from sys_cs_conversation table.',
|
|
144
|
+
inputSchema: {
|
|
145
|
+
type: 'object',
|
|
146
|
+
properties: {
|
|
147
|
+
conversation_id: { type: 'string', description: 'Conversation sys_id' },
|
|
148
|
+
user: { type: 'string', description: 'Filter by user' },
|
|
149
|
+
limit: { type: 'number', default: 50 }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'snow_send_va_message',
|
|
155
|
+
description: 'Sends message to virtual agent using sys_cs_conversation table.',
|
|
156
|
+
inputSchema: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
properties: {
|
|
159
|
+
conversation_id: { type: 'string', description: 'Conversation ID' },
|
|
160
|
+
message: { type: 'string', description: 'User message' },
|
|
161
|
+
user: { type: 'string', description: 'User sys_id' }
|
|
162
|
+
},
|
|
163
|
+
required: ['message']
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'snow_handoff_to_agent',
|
|
168
|
+
description: 'Escalates conversation to live agent using sys_cs_conversation table.',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
conversation_id: { type: 'string', description: 'Conversation to escalate' },
|
|
173
|
+
reason: { type: 'string', description: 'Escalation reason' },
|
|
174
|
+
priority: { type: 'string', description: 'Priority level' }
|
|
175
|
+
},
|
|
176
|
+
required: ['conversation_id']
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: 'snow_discover_va_topics',
|
|
181
|
+
description: 'Lists all virtual agent topics from sys_cs_topic table.',
|
|
182
|
+
inputSchema: {
|
|
183
|
+
type: 'object',
|
|
184
|
+
properties: {
|
|
185
|
+
active_only: { type: 'boolean', default: true },
|
|
186
|
+
category: { type: 'string', description: 'Filter by category' }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
// Performance Analytics Tools
|
|
191
|
+
{
|
|
192
|
+
name: 'snow_create_pa_indicator',
|
|
193
|
+
description: 'Creates PA indicator using pa_indicators table.',
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: 'object',
|
|
196
|
+
properties: {
|
|
197
|
+
name: { type: 'string', description: 'Indicator name' },
|
|
198
|
+
table: { type: 'string', description: 'Source table' },
|
|
199
|
+
aggregate: { type: 'string', description: 'Aggregation: COUNT, SUM, AVG' },
|
|
200
|
+
field: { type: 'string', description: 'Field to aggregate' },
|
|
201
|
+
conditions: { type: 'string', description: 'Filter conditions' },
|
|
202
|
+
frequency: { type: 'string', description: 'daily, weekly, monthly' }
|
|
203
|
+
},
|
|
204
|
+
required: ['name', 'table', 'aggregate']
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'snow_create_pa_widget',
|
|
209
|
+
description: 'Creates PA dashboard widget using pa_widgets table.',
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
name: { type: 'string', description: 'Widget name' },
|
|
214
|
+
indicator: { type: 'string', description: 'Indicator sys_id' },
|
|
215
|
+
type: { type: 'string', description: 'line, bar, pie, single_score' },
|
|
216
|
+
size: { type: 'string', description: 'small, medium, large' },
|
|
217
|
+
time_range: { type: 'string', description: 'Time range' }
|
|
218
|
+
},
|
|
219
|
+
required: ['name', 'indicator', 'type']
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: 'snow_create_pa_breakdown',
|
|
224
|
+
description: 'Creates PA breakdown using pa_breakdowns table.',
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties: {
|
|
228
|
+
name: { type: 'string', description: 'Breakdown name' },
|
|
229
|
+
source_table: { type: 'string', description: 'Source table' },
|
|
230
|
+
field: { type: 'string', description: 'Field to break down by' },
|
|
231
|
+
related_indicator: { type: 'string', description: 'Related indicator sys_id' }
|
|
232
|
+
},
|
|
233
|
+
required: ['name', 'source_table', 'field']
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'snow_create_pa_threshold',
|
|
238
|
+
description: 'Creates PA threshold using pa_thresholds table.',
|
|
239
|
+
inputSchema: {
|
|
240
|
+
type: 'object',
|
|
241
|
+
properties: {
|
|
242
|
+
indicator: { type: 'string', description: 'Indicator sys_id' },
|
|
243
|
+
value: { type: 'number', description: 'Threshold value' },
|
|
244
|
+
direction: { type: 'string', description: 'above, below' },
|
|
245
|
+
color: { type: 'string', description: 'red, yellow, green' },
|
|
246
|
+
send_alert: { type: 'boolean', default: false }
|
|
247
|
+
},
|
|
248
|
+
required: ['indicator', 'value', 'direction']
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'snow_get_pa_scores',
|
|
253
|
+
description: 'Gets PA scores from pa_scores table.',
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: 'object',
|
|
256
|
+
properties: {
|
|
257
|
+
indicator: { type: 'string', description: 'Indicator sys_id' },
|
|
258
|
+
start_date: { type: 'string', description: 'Start date' },
|
|
259
|
+
end_date: { type: 'string', description: 'End date' },
|
|
260
|
+
breakdown: { type: 'string', description: 'Breakdown sys_id' }
|
|
261
|
+
},
|
|
262
|
+
required: ['indicator']
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'snow_create_pa_target',
|
|
267
|
+
description: 'Creates PA target using pa_targets table.',
|
|
268
|
+
inputSchema: {
|
|
269
|
+
type: 'object',
|
|
270
|
+
properties: {
|
|
271
|
+
indicator: { type: 'string', description: 'Indicator sys_id' },
|
|
272
|
+
target_value: { type: 'number', description: 'Target value' },
|
|
273
|
+
period: { type: 'string', description: 'monthly, quarterly, yearly' },
|
|
274
|
+
start_date: { type: 'string', description: 'Target start date' }
|
|
275
|
+
},
|
|
276
|
+
required: ['indicator', 'target_value']
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: 'snow_analyze_pa_trends',
|
|
281
|
+
description: 'Analyzes PA trends from pa_scores table.',
|
|
282
|
+
inputSchema: {
|
|
283
|
+
type: 'object',
|
|
284
|
+
properties: {
|
|
285
|
+
indicator: { type: 'string', description: 'Indicator sys_id' },
|
|
286
|
+
period: { type: 'string', description: 'Analysis period' },
|
|
287
|
+
include_forecast: { type: 'boolean', default: false }
|
|
288
|
+
},
|
|
289
|
+
required: ['indicator']
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
}));
|
|
294
|
+
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
295
|
+
try {
|
|
296
|
+
const { name, arguments: args } = request.params;
|
|
297
|
+
// Execute with enhanced tracking
|
|
298
|
+
return await this.executeTool(name, async () => {
|
|
299
|
+
switch (name) {
|
|
300
|
+
// Change Management
|
|
301
|
+
case 'snow_create_change_request':
|
|
302
|
+
return await this.createChangeRequest(args);
|
|
303
|
+
case 'snow_create_change_task':
|
|
304
|
+
return await this.createChangeTask(args);
|
|
305
|
+
case 'snow_get_change_request':
|
|
306
|
+
return await this.getChangeRequest(args);
|
|
307
|
+
case 'snow_update_change_state':
|
|
308
|
+
return await this.updateChangeState(args);
|
|
309
|
+
case 'snow_schedule_cab_meeting':
|
|
310
|
+
return await this.scheduleCabMeeting(args);
|
|
311
|
+
case 'snow_search_change_requests':
|
|
312
|
+
return await this.searchChangeRequests(args);
|
|
313
|
+
// Virtual Agent
|
|
314
|
+
case 'snow_create_va_topic':
|
|
315
|
+
return await this.createVATopic(args);
|
|
316
|
+
case 'snow_create_va_topic_block':
|
|
317
|
+
return await this.createVATopicBlock(args);
|
|
318
|
+
case 'snow_get_va_conversation':
|
|
319
|
+
return await this.getVAConversation(args);
|
|
320
|
+
case 'snow_send_va_message':
|
|
321
|
+
return await this.sendVAMessage(args);
|
|
322
|
+
case 'snow_handoff_to_agent':
|
|
323
|
+
return await this.handoffToAgent(args);
|
|
324
|
+
case 'snow_discover_va_topics':
|
|
325
|
+
return await this.discoverVATopics(args);
|
|
326
|
+
// Performance Analytics
|
|
327
|
+
case 'snow_create_pa_indicator':
|
|
328
|
+
return await this.createPAIndicator(args);
|
|
329
|
+
case 'snow_create_pa_widget':
|
|
330
|
+
return await this.createPAWidget(args);
|
|
331
|
+
case 'snow_create_pa_breakdown':
|
|
332
|
+
return await this.createPABreakdown(args);
|
|
333
|
+
case 'snow_create_pa_threshold':
|
|
334
|
+
return await this.createPAThreshold(args);
|
|
335
|
+
case 'snow_get_pa_scores':
|
|
336
|
+
return await this.getPAScores(args);
|
|
337
|
+
case 'snow_create_pa_target':
|
|
338
|
+
return await this.createPATarget(args);
|
|
339
|
+
case 'snow_analyze_pa_trends':
|
|
340
|
+
return await this.analyzePATrends(args);
|
|
341
|
+
default:
|
|
342
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
if (error instanceof types_js_1.McpError)
|
|
348
|
+
throw error;
|
|
349
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Tool execution failed: ${error}`);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
// Change Management Methods
|
|
354
|
+
async createChangeRequest(args) {
|
|
355
|
+
this.logger.info('Creating change request...', {
|
|
356
|
+
short_description: args.short_description,
|
|
357
|
+
type: args.type,
|
|
358
|
+
risk: args.risk
|
|
359
|
+
});
|
|
360
|
+
const changeData = {
|
|
361
|
+
short_description: args.short_description,
|
|
362
|
+
description: args.description || '',
|
|
363
|
+
type: args.type,
|
|
364
|
+
risk: args.risk || 'moderate',
|
|
365
|
+
impact: args.impact || '3',
|
|
366
|
+
implementation_plan: args.implementation_plan || '',
|
|
367
|
+
backout_plan: args.backout_plan || '',
|
|
368
|
+
test_plan: args.test_plan || '',
|
|
369
|
+
justification: args.justification || '',
|
|
370
|
+
start_date: args.start_date || '',
|
|
371
|
+
end_date: args.end_date || '',
|
|
372
|
+
state: 'new'
|
|
373
|
+
};
|
|
374
|
+
this.logger.progress('Creating change request in ServiceNow...');
|
|
375
|
+
const response = await this.createRecord('change_request', changeData);
|
|
376
|
+
if (!response.success) {
|
|
377
|
+
return this.createResponse(`ā Failed to create change: ${response.error}`);
|
|
378
|
+
}
|
|
379
|
+
const result = response.data;
|
|
380
|
+
this.logger.info('ā
Change request created', {
|
|
381
|
+
number: result.number,
|
|
382
|
+
sys_id: result.sys_id
|
|
383
|
+
});
|
|
384
|
+
return this.createResponse(`ā
Change Request created!
|
|
385
|
+
š **${result.number}**
|
|
386
|
+
š§ Type: ${args.type}
|
|
387
|
+
ā ļø Risk: ${args.risk || 'moderate'}
|
|
388
|
+
š Impact: ${args.impact || '3-moderate'}
|
|
389
|
+
š sys_id: ${result.sys_id}
|
|
390
|
+
š
Schedule: ${args.start_date || 'TBD'} - ${args.end_date || 'TBD'}
|
|
391
|
+
|
|
392
|
+
⨠Change request ready for assessment!`);
|
|
393
|
+
}
|
|
394
|
+
async createChangeTask(args) {
|
|
395
|
+
this.logger.info('Creating change task...', { change_request: args.change_request });
|
|
396
|
+
const taskData = {
|
|
397
|
+
change_request: args.change_request,
|
|
398
|
+
short_description: args.short_description,
|
|
399
|
+
assignment_group: args.assignment_group || '',
|
|
400
|
+
assigned_to: args.assigned_to || '',
|
|
401
|
+
order: args.order || 100,
|
|
402
|
+
state: 'pending'
|
|
403
|
+
};
|
|
404
|
+
this.logger.progress('Creating task...');
|
|
405
|
+
const response = await this.createRecord('change_task', taskData);
|
|
406
|
+
if (!response.success) {
|
|
407
|
+
return this.createResponse(`ā Failed to create task: ${response.error}`);
|
|
408
|
+
}
|
|
409
|
+
this.logger.info('ā
Change task created');
|
|
410
|
+
return this.createResponse(`ā
Change task created!
|
|
411
|
+
š ${args.short_description}
|
|
412
|
+
š sys_id: ${response.data.sys_id}
|
|
413
|
+
š Order: ${args.order || 100}`);
|
|
414
|
+
}
|
|
415
|
+
async getChangeRequest(args) {
|
|
416
|
+
this.logger.info('Getting change request...', { sys_id: args.sys_id });
|
|
417
|
+
const response = await this.getRecord('change_request', args.sys_id);
|
|
418
|
+
if (!response.success) {
|
|
419
|
+
return this.createResponse(`ā Failed to get change: ${response.error}`);
|
|
420
|
+
}
|
|
421
|
+
const change = response.data;
|
|
422
|
+
let details = `š **${change.number}**
|
|
423
|
+
š§ Type: ${change.type}
|
|
424
|
+
ā ļø Risk: ${change.risk}
|
|
425
|
+
š State: ${change.state}
|
|
426
|
+
š
Schedule: ${change.start_date} - ${change.end_date}
|
|
427
|
+
š sys_id: ${change.sys_id}`;
|
|
428
|
+
if (args.include_tasks) {
|
|
429
|
+
const taskQuery = `change_request=${args.sys_id}`;
|
|
430
|
+
const taskResponse = await this.queryTable('change_task', taskQuery, 20);
|
|
431
|
+
if (taskResponse.success && taskResponse.data.result.length > 0) {
|
|
432
|
+
details += `\n\nš Tasks (${taskResponse.data.result.length}):`;
|
|
433
|
+
taskResponse.data.result.forEach((task) => {
|
|
434
|
+
details += `\n ⢠${task.short_description} (${task.state})`;
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
this.logger.info('ā
Retrieved change details');
|
|
439
|
+
return this.createResponse(details);
|
|
440
|
+
}
|
|
441
|
+
async updateChangeState(args) {
|
|
442
|
+
this.logger.info('Updating change state...', {
|
|
443
|
+
sys_id: args.sys_id,
|
|
444
|
+
state: args.state
|
|
445
|
+
});
|
|
446
|
+
const updateData = { state: args.state };
|
|
447
|
+
if (args.close_notes)
|
|
448
|
+
updateData.close_notes = args.close_notes;
|
|
449
|
+
const response = await this.updateRecord('change_request', args.sys_id, updateData);
|
|
450
|
+
if (!response.success) {
|
|
451
|
+
return this.createResponse(`ā Failed to update state: ${response.error}`);
|
|
452
|
+
}
|
|
453
|
+
this.logger.info('ā
Change state updated');
|
|
454
|
+
return this.createResponse(`ā
Change state updated to: ${args.state}
|
|
455
|
+
š sys_id: ${args.sys_id}`);
|
|
456
|
+
}
|
|
457
|
+
async scheduleCabMeeting(args) {
|
|
458
|
+
this.logger.info('Scheduling CAB meeting...', { date: args.meeting_date });
|
|
459
|
+
const meetingData = {
|
|
460
|
+
meeting_date: args.meeting_date,
|
|
461
|
+
location: args.location || 'Virtual',
|
|
462
|
+
state: 'scheduled'
|
|
463
|
+
};
|
|
464
|
+
this.logger.progress('Creating CAB meeting...');
|
|
465
|
+
const response = await this.createRecord('cab_meeting', meetingData);
|
|
466
|
+
if (!response.success) {
|
|
467
|
+
return this.createResponse(`ā Failed to schedule CAB: ${response.error}`);
|
|
468
|
+
}
|
|
469
|
+
const meeting = response.data;
|
|
470
|
+
// Add change requests to agenda
|
|
471
|
+
if (args.change_requests && args.change_requests.length > 0) {
|
|
472
|
+
for (const changeId of args.change_requests) {
|
|
473
|
+
await this.createRecord('cab_agenda_item', {
|
|
474
|
+
cab_meeting: meeting.sys_id,
|
|
475
|
+
change_request: changeId
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
this.logger.info('ā
CAB meeting scheduled');
|
|
480
|
+
return this.createResponse(`ā
CAB Meeting scheduled!
|
|
481
|
+
š
Date: ${args.meeting_date}
|
|
482
|
+
š Location: ${args.location || 'Virtual'}
|
|
483
|
+
š Changes: ${args.change_requests?.length || 0} items
|
|
484
|
+
š sys_id: ${meeting.sys_id}`);
|
|
485
|
+
}
|
|
486
|
+
async searchChangeRequests(args) {
|
|
487
|
+
this.logger.info('Searching change requests...', { query: args.query });
|
|
488
|
+
let query = args.query ? `short_descriptionLIKE${args.query}` : '';
|
|
489
|
+
if (args.state)
|
|
490
|
+
query += `^state=${args.state}`;
|
|
491
|
+
if (args.type)
|
|
492
|
+
query += `^type=${args.type}`;
|
|
493
|
+
if (args.risk)
|
|
494
|
+
query += `^risk=${args.risk}`;
|
|
495
|
+
this.logger.progress('Searching changes...');
|
|
496
|
+
const response = await this.queryTable('change_request', query, args.limit || 10);
|
|
497
|
+
if (!response.success) {
|
|
498
|
+
return this.createResponse(`ā Search failed: ${response.error}`);
|
|
499
|
+
}
|
|
500
|
+
const changes = response.data.result;
|
|
501
|
+
if (!changes.length) {
|
|
502
|
+
return this.createResponse(`ā No changes found`);
|
|
503
|
+
}
|
|
504
|
+
this.logger.info(`Found ${changes.length} changes`);
|
|
505
|
+
const changeList = changes.map((c) => `š **${c.number}** - ${c.short_description}
|
|
506
|
+
š§ ${c.type} | ā ļø ${c.risk} | š ${c.state}`).join('\n\n');
|
|
507
|
+
return this.createResponse(`š Change Requests:\n\n${changeList}\n\n⨠Found ${changes.length} change(s)`);
|
|
508
|
+
}
|
|
509
|
+
// Virtual Agent Methods
|
|
510
|
+
async createVATopic(args) {
|
|
511
|
+
this.logger.info('Creating VA topic...', { name: args.name });
|
|
512
|
+
const topicData = {
|
|
513
|
+
name: args.name,
|
|
514
|
+
description: args.description || '',
|
|
515
|
+
trigger_phrases: args.trigger_phrases.join(','),
|
|
516
|
+
category: args.category || '',
|
|
517
|
+
active: args.active !== false
|
|
518
|
+
};
|
|
519
|
+
this.logger.progress('Creating topic...');
|
|
520
|
+
const response = await this.createRecord('sys_cs_topic', topicData);
|
|
521
|
+
if (!response.success) {
|
|
522
|
+
return this.createResponse(`ā Failed to create topic: ${response.error}`);
|
|
523
|
+
}
|
|
524
|
+
this.logger.info('ā
VA topic created');
|
|
525
|
+
return this.createResponse(`ā
Virtual Agent topic created!
|
|
526
|
+
š¤ **${args.name}**
|
|
527
|
+
š¬ Triggers: ${args.trigger_phrases.join(', ')}
|
|
528
|
+
š sys_id: ${response.data.sys_id}`);
|
|
529
|
+
}
|
|
530
|
+
async createVATopicBlock(args) {
|
|
531
|
+
this.logger.info('Creating topic block...', { topic: args.topic, type: args.type });
|
|
532
|
+
const blockData = {
|
|
533
|
+
topic: args.topic,
|
|
534
|
+
type: args.type,
|
|
535
|
+
message: args.message,
|
|
536
|
+
order: args.order || 100,
|
|
537
|
+
options: JSON.stringify(args.options || [])
|
|
538
|
+
};
|
|
539
|
+
this.logger.progress('Creating block...');
|
|
540
|
+
const response = await this.createRecord('sys_cs_topic_block', blockData);
|
|
541
|
+
if (!response.success) {
|
|
542
|
+
return this.createResponse(`ā Failed to create block: ${response.error}`);
|
|
543
|
+
}
|
|
544
|
+
this.logger.info('ā
Topic block created');
|
|
545
|
+
return this.createResponse(`ā
Topic block created!
|
|
546
|
+
š Type: ${args.type}
|
|
547
|
+
š¬ Message: ${args.message}
|
|
548
|
+
š sys_id: ${response.data.sys_id}`);
|
|
549
|
+
}
|
|
550
|
+
async getVAConversation(args) {
|
|
551
|
+
this.logger.info('Getting VA conversation...');
|
|
552
|
+
let query = '';
|
|
553
|
+
if (args.conversation_id)
|
|
554
|
+
query = `sys_id=${args.conversation_id}`;
|
|
555
|
+
else if (args.user)
|
|
556
|
+
query = `user=${args.user}`;
|
|
557
|
+
const response = await this.queryTable('sys_cs_conversation', query, args.limit || 50);
|
|
558
|
+
if (!response.success) {
|
|
559
|
+
return this.createResponse(`ā Failed to get conversation: ${response.error}`);
|
|
560
|
+
}
|
|
561
|
+
const messages = response.data.result;
|
|
562
|
+
this.logger.info(`Retrieved ${messages.length} messages`);
|
|
563
|
+
const conversation = messages.map((msg) => `[${msg.sys_created_on}] ${msg.from_user ? 'š¤' : 'š¤'} ${msg.message}`).join('\n');
|
|
564
|
+
return this.createResponse(`š¬ Conversation History:\n\n${conversation}\n\n⨠${messages.length} messages`);
|
|
565
|
+
}
|
|
566
|
+
async sendVAMessage(args) {
|
|
567
|
+
this.logger.info('Sending VA message...', { message: args.message });
|
|
568
|
+
const messageData = {
|
|
569
|
+
conversation: args.conversation_id || '',
|
|
570
|
+
message: args.message,
|
|
571
|
+
user: args.user || 'api_user',
|
|
572
|
+
from_user: true
|
|
573
|
+
};
|
|
574
|
+
this.logger.progress('Sending message...');
|
|
575
|
+
const response = await this.createRecord('sys_cs_conversation', messageData);
|
|
576
|
+
if (!response.success) {
|
|
577
|
+
return this.createResponse(`ā Failed to send message: ${response.error}`);
|
|
578
|
+
}
|
|
579
|
+
this.logger.info('ā
Message sent');
|
|
580
|
+
return this.createResponse(`ā
Message sent to Virtual Agent!
|
|
581
|
+
š¬ "${args.message}"
|
|
582
|
+
š Conversation: ${response.data.conversation || response.data.sys_id}`);
|
|
583
|
+
}
|
|
584
|
+
async handoffToAgent(args) {
|
|
585
|
+
this.logger.info('Escalating to live agent...', { conversation_id: args.conversation_id });
|
|
586
|
+
const updateData = {
|
|
587
|
+
state: 'escalated',
|
|
588
|
+
escalation_reason: args.reason || 'User requested agent',
|
|
589
|
+
priority: args.priority || '3'
|
|
590
|
+
};
|
|
591
|
+
const response = await this.updateRecord('sys_cs_conversation', args.conversation_id, updateData);
|
|
592
|
+
if (!response.success) {
|
|
593
|
+
return this.createResponse(`ā Failed to escalate: ${response.error}`);
|
|
594
|
+
}
|
|
595
|
+
this.logger.info('ā
Escalated to agent');
|
|
596
|
+
return this.createResponse(`ā
Conversation escalated to live agent!
|
|
597
|
+
š Reason: ${args.reason || 'User requested'}
|
|
598
|
+
ā” Priority: ${args.priority || '3-moderate'}`);
|
|
599
|
+
}
|
|
600
|
+
async discoverVATopics(args) {
|
|
601
|
+
this.logger.info('Discovering VA topics...');
|
|
602
|
+
let query = args.active_only ? 'active=true' : '';
|
|
603
|
+
if (args.category)
|
|
604
|
+
query += `^category=${args.category}`;
|
|
605
|
+
const response = await this.queryTable('sys_cs_topic', query, 50);
|
|
606
|
+
if (!response.success) {
|
|
607
|
+
return this.createResponse(`ā Failed to discover topics: ${response.error}`);
|
|
608
|
+
}
|
|
609
|
+
const topics = response.data.result;
|
|
610
|
+
this.logger.info(`Found ${topics.length} topics`);
|
|
611
|
+
const topicList = topics.map((topic) => `š¤ **${topic.name}**
|
|
612
|
+
š ${topic.description || 'No description'}
|
|
613
|
+
š·ļø ${topic.category || 'Uncategorized'}`).join('\n\n');
|
|
614
|
+
return this.createResponse(`š¤ Virtual Agent Topics:\n\n${topicList}\n\n⨠Total: ${topics.length} topics`);
|
|
615
|
+
}
|
|
616
|
+
// Performance Analytics Methods
|
|
617
|
+
async createPAIndicator(args) {
|
|
618
|
+
this.logger.info('Creating PA indicator...', {
|
|
619
|
+
name: args.name,
|
|
620
|
+
table: args.table,
|
|
621
|
+
aggregate: args.aggregate
|
|
622
|
+
});
|
|
623
|
+
const indicatorData = {
|
|
624
|
+
name: args.name,
|
|
625
|
+
table: args.table,
|
|
626
|
+
aggregate: args.aggregate,
|
|
627
|
+
field: args.field || '',
|
|
628
|
+
conditions: args.conditions || '',
|
|
629
|
+
frequency: args.frequency || 'daily',
|
|
630
|
+
active: true
|
|
631
|
+
};
|
|
632
|
+
this.logger.progress('Creating indicator...');
|
|
633
|
+
const response = await this.createRecord('pa_indicators', indicatorData);
|
|
634
|
+
if (!response.success) {
|
|
635
|
+
return this.createResponse(`ā Failed to create indicator: ${response.error}`);
|
|
636
|
+
}
|
|
637
|
+
this.logger.info('ā
PA indicator created');
|
|
638
|
+
return this.createResponse(`ā
PA Indicator created!
|
|
639
|
+
š **${args.name}**
|
|
640
|
+
š Table: ${args.table}
|
|
641
|
+
š Aggregate: ${args.aggregate}${args.field ? ` on ${args.field}` : ''}
|
|
642
|
+
ā° Frequency: ${args.frequency || 'daily'}
|
|
643
|
+
š sys_id: ${response.data.sys_id}`);
|
|
644
|
+
}
|
|
645
|
+
async createPAWidget(args) {
|
|
646
|
+
this.logger.info('Creating PA widget...', {
|
|
647
|
+
name: args.name,
|
|
648
|
+
type: args.type
|
|
649
|
+
});
|
|
650
|
+
const widgetData = {
|
|
651
|
+
name: args.name,
|
|
652
|
+
indicator: args.indicator,
|
|
653
|
+
type: args.type,
|
|
654
|
+
size: args.size || 'medium',
|
|
655
|
+
time_range: args.time_range || '30 days'
|
|
656
|
+
};
|
|
657
|
+
this.logger.progress('Creating widget...');
|
|
658
|
+
const response = await this.createRecord('pa_widgets', widgetData);
|
|
659
|
+
if (!response.success) {
|
|
660
|
+
return this.createResponse(`ā Failed to create widget: ${response.error}`);
|
|
661
|
+
}
|
|
662
|
+
this.logger.info('ā
PA widget created');
|
|
663
|
+
return this.createResponse(`ā
PA Widget created!
|
|
664
|
+
š **${args.name}**
|
|
665
|
+
š Type: ${args.type}
|
|
666
|
+
š Size: ${args.size || 'medium'}
|
|
667
|
+
ā° Range: ${args.time_range || '30 days'}
|
|
668
|
+
š sys_id: ${response.data.sys_id}`);
|
|
669
|
+
}
|
|
670
|
+
async createPABreakdown(args) {
|
|
671
|
+
this.logger.info('Creating PA breakdown...', { name: args.name });
|
|
672
|
+
const breakdownData = {
|
|
673
|
+
name: args.name,
|
|
674
|
+
source_table: args.source_table,
|
|
675
|
+
field: args.field,
|
|
676
|
+
related_indicator: args.related_indicator || ''
|
|
677
|
+
};
|
|
678
|
+
this.logger.progress('Creating breakdown...');
|
|
679
|
+
const response = await this.createRecord('pa_breakdowns', breakdownData);
|
|
680
|
+
if (!response.success) {
|
|
681
|
+
return this.createResponse(`ā Failed to create breakdown: ${response.error}`);
|
|
682
|
+
}
|
|
683
|
+
this.logger.info('ā
PA breakdown created');
|
|
684
|
+
return this.createResponse(`ā
PA Breakdown created!
|
|
685
|
+
š **${args.name}**
|
|
686
|
+
š Table: ${args.source_table}
|
|
687
|
+
š Field: ${args.field}
|
|
688
|
+
š sys_id: ${response.data.sys_id}`);
|
|
689
|
+
}
|
|
690
|
+
async createPAThreshold(args) {
|
|
691
|
+
this.logger.info('Creating PA threshold...', {
|
|
692
|
+
indicator: args.indicator,
|
|
693
|
+
value: args.value
|
|
694
|
+
});
|
|
695
|
+
const thresholdData = {
|
|
696
|
+
indicator: args.indicator,
|
|
697
|
+
value: args.value,
|
|
698
|
+
direction: args.direction,
|
|
699
|
+
color: args.color || 'yellow',
|
|
700
|
+
send_alert: args.send_alert || false
|
|
701
|
+
};
|
|
702
|
+
this.logger.progress('Creating threshold...');
|
|
703
|
+
const response = await this.createRecord('pa_thresholds', thresholdData);
|
|
704
|
+
if (!response.success) {
|
|
705
|
+
return this.createResponse(`ā Failed to create threshold: ${response.error}`);
|
|
706
|
+
}
|
|
707
|
+
this.logger.info('ā
PA threshold created');
|
|
708
|
+
return this.createResponse(`ā
PA Threshold created!
|
|
709
|
+
ā ļø Value: ${args.value} (${args.direction})
|
|
710
|
+
šØ Color: ${args.color || 'yellow'}
|
|
711
|
+
š Alert: ${args.send_alert ? 'Yes' : 'No'}
|
|
712
|
+
š sys_id: ${response.data.sys_id}`);
|
|
713
|
+
}
|
|
714
|
+
async getPAScores(args) {
|
|
715
|
+
this.logger.info('Getting PA scores...', { indicator: args.indicator });
|
|
716
|
+
let query = `indicator=${args.indicator}`;
|
|
717
|
+
if (args.start_date)
|
|
718
|
+
query += `^sys_created_on>=${args.start_date}`;
|
|
719
|
+
if (args.end_date)
|
|
720
|
+
query += `^sys_created_on<=${args.end_date}`;
|
|
721
|
+
if (args.breakdown)
|
|
722
|
+
query += `^breakdown=${args.breakdown}`;
|
|
723
|
+
this.logger.progress('Retrieving scores...');
|
|
724
|
+
const response = await this.queryTable('pa_scores', query, 100);
|
|
725
|
+
if (!response.success) {
|
|
726
|
+
return this.createResponse(`ā Failed to get scores: ${response.error}`);
|
|
727
|
+
}
|
|
728
|
+
const scores = response.data.result;
|
|
729
|
+
if (!scores.length) {
|
|
730
|
+
return this.createResponse(`ā No scores found for indicator`);
|
|
731
|
+
}
|
|
732
|
+
this.logger.info(`Retrieved ${scores.length} scores`);
|
|
733
|
+
// Calculate statistics
|
|
734
|
+
const values = scores.map((s) => parseFloat(s.value));
|
|
735
|
+
const avg = (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2);
|
|
736
|
+
const min = Math.min(...values);
|
|
737
|
+
const max = Math.max(...values);
|
|
738
|
+
return this.createResponse(`š PA Scores:
|
|
739
|
+
š Average: ${avg}
|
|
740
|
+
ā¬ļø Min: ${min}
|
|
741
|
+
ā¬ļø Max: ${max}
|
|
742
|
+
š
Period: ${scores.length} data points
|
|
743
|
+
⨠Latest: ${values[values.length - 1]}`);
|
|
744
|
+
}
|
|
745
|
+
async createPATarget(args) {
|
|
746
|
+
this.logger.info('Creating PA target...', {
|
|
747
|
+
indicator: args.indicator,
|
|
748
|
+
target_value: args.target_value
|
|
749
|
+
});
|
|
750
|
+
const targetData = {
|
|
751
|
+
indicator: args.indicator,
|
|
752
|
+
target_value: args.target_value,
|
|
753
|
+
period: args.period || 'monthly',
|
|
754
|
+
start_date: args.start_date || new Date().toISOString()
|
|
755
|
+
};
|
|
756
|
+
this.logger.progress('Creating target...');
|
|
757
|
+
const response = await this.createRecord('pa_targets', targetData);
|
|
758
|
+
if (!response.success) {
|
|
759
|
+
return this.createResponse(`ā Failed to create target: ${response.error}`);
|
|
760
|
+
}
|
|
761
|
+
this.logger.info('ā
PA target created');
|
|
762
|
+
return this.createResponse(`ā
PA Target created!
|
|
763
|
+
šÆ Target: ${args.target_value}
|
|
764
|
+
š
Period: ${args.period || 'monthly'}
|
|
765
|
+
š Start: ${args.start_date || 'Today'}
|
|
766
|
+
š sys_id: ${response.data.sys_id}`);
|
|
767
|
+
}
|
|
768
|
+
async analyzePATrends(args) {
|
|
769
|
+
this.logger.info('Analyzing PA trends...', { indicator: args.indicator });
|
|
770
|
+
const query = `indicator=${args.indicator}^ORDERBYsys_created_on`;
|
|
771
|
+
const response = await this.queryTable('pa_scores', query, 100);
|
|
772
|
+
if (!response.success) {
|
|
773
|
+
return this.createResponse(`ā Failed to analyze trends: ${response.error}`);
|
|
774
|
+
}
|
|
775
|
+
const scores = response.data.result;
|
|
776
|
+
if (scores.length < 2) {
|
|
777
|
+
return this.createResponse(`ā Insufficient data for trend analysis`);
|
|
778
|
+
}
|
|
779
|
+
this.logger.info(`Analyzing ${scores.length} data points`);
|
|
780
|
+
// Calculate trend
|
|
781
|
+
const values = scores.map((s) => parseFloat(s.value));
|
|
782
|
+
const firstHalf = values.slice(0, Math.floor(values.length / 2));
|
|
783
|
+
const secondHalf = values.slice(Math.floor(values.length / 2));
|
|
784
|
+
const firstAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
|
|
785
|
+
const secondAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;
|
|
786
|
+
const trend = ((secondAvg - firstAvg) / firstAvg * 100).toFixed(1);
|
|
787
|
+
const direction = parseFloat(trend) > 0 ? 'š Upward' : parseFloat(trend) < 0 ? 'š Downward' : 'ā”ļø Stable';
|
|
788
|
+
let analysis = `š Trend Analysis:
|
|
789
|
+
${direction} trend: ${Math.abs(parseFloat(trend))}%
|
|
790
|
+
š
Period: ${scores.length} data points
|
|
791
|
+
š Current: ${values[values.length - 1]}
|
|
792
|
+
š Previous: ${values[values.length - 2]}`;
|
|
793
|
+
if (args.include_forecast) {
|
|
794
|
+
// Simple linear forecast
|
|
795
|
+
const growthRate = parseFloat(trend) / 100;
|
|
796
|
+
const forecast = (values[values.length - 1] * (1 + growthRate)).toFixed(2);
|
|
797
|
+
analysis += `\nš® Next Period Forecast: ${forecast}`;
|
|
798
|
+
}
|
|
799
|
+
return this.createResponse(analysis);
|
|
800
|
+
}
|
|
801
|
+
async start() {
|
|
802
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
803
|
+
await this.server.connect(transport);
|
|
804
|
+
// Log ready state
|
|
805
|
+
this.logger.info('š ServiceNow Change, VA & PA MCP Server (Enhanced) running');
|
|
806
|
+
this.logger.info('š Token tracking enabled');
|
|
807
|
+
this.logger.info('ā³ Progress indicators active');
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// Start the enhanced server
|
|
811
|
+
const server = new ServiceNowChangeVirtualAgentPAMCPEnhanced();
|
|
812
|
+
server.start().catch((error) => {
|
|
813
|
+
console.error('Failed to start enhanced server:', error);
|
|
814
|
+
process.exit(1);
|
|
815
|
+
});
|
|
816
|
+
//# sourceMappingURL=servicenow-change-virtualagent-pa-mcp-enhanced.js.map
|