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.
@@ -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