snow-flow 1.3.1 → 1.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/.claude-flow/queen/queen-memory.db +0 -0
- package/.env.example +249 -14
- package/CLAUDE.md +185 -24
- package/README.md +55 -5
- package/dist/api/error-handling.js +898 -4
- package/dist/api/performance-optimizer.js +3 -2
- package/dist/cli.js +590 -200
- package/dist/config/snow-flow-config.js +320 -8
- package/dist/health/system-health.js +288 -21
- package/dist/mcp/http-transport-wrapper.js +65 -4
- package/dist/mcp/servicenow-automation-mcp-refactored.js +90 -9
- package/dist/mcp/servicenow-deployment-mcp-refactored.js +151 -2
- package/dist/mcp/servicenow-deployment-mcp.js +828 -15
- package/dist/mcp/servicenow-integration-mcp-refactored.js +100 -9
- package/dist/mcp/servicenow-intelligent-mcp.js +198 -7
- package/dist/mcp/servicenow-memory-mcp.js +2 -1
- package/dist/mcp/servicenow-operations-mcp-refactored.js +3 -2
- package/dist/mcp/servicenow-xml-flow-mcp.js +671 -0
- package/dist/mcp/shared/base-mcp-server.js +1356 -8
- package/dist/mcp/shared/mcp-resource-manager.js +304 -0
- package/dist/queen/parallel-agent-engine.js +26 -8
- package/dist/queen/servicenow-queen.js +47 -44
- package/dist/sparc/sparc-help.js +37 -26
- package/dist/sparc/team-sparc.js +60 -16
- package/dist/utils/action-type-cache.js +2 -1
- package/dist/utils/mcp-config-manager.js +7 -3
- package/dist/utils/mcp-server-manager.js +7 -3
- package/dist/utils/servicenow-client.js +134 -107
- package/dist/utils/servicenow-id-generator.js +171 -0
- package/dist/utils/snow-oauth.js +13 -8
- package/dist/utils/widget-template-generator.js +1690 -0
- package/dist/utils/xml-first-flow-generator.js +473 -0
- package/flow-update-sets/flow_build_automated_approval_flow_with_notifications_flow.xml +203 -0
- package/flow-update-sets/flow_create_approval_flow_for_equipment_requests_flow.xml +206 -0
- package/flow-update-sets/flow_create_equipment_approval_flow_with_manager_approv_flow.xml +254 -0
- package/flow-update-sets/iphone_15_pro_approval_flow.xml +203 -0
- package/flow-update-sets/test_iphone_approval_flow_flow.xml +303 -0
- package/package.json +2 -1
- package/test-config.js +55 -0
- package/test-real-monitoring.js +184 -0
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ServiceNow XML Flow MCP Server
|
|
5
|
+
* Provides XML-first flow generation capabilities
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.ServiceNowXMLFlowMCP = void 0;
|
|
42
|
+
const base_mcp_server_1 = require("./base-mcp-server");
|
|
43
|
+
const xml_first_flow_generator_1 = __importStar(require("../utils/xml-first-flow-generator"));
|
|
44
|
+
const natural_language_mapper_1 = require("../api/natural-language-mapper");
|
|
45
|
+
const servicenow_id_generator_js_1 = require("../utils/servicenow-id-generator.js");
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
|
|
49
|
+
constructor() {
|
|
50
|
+
super({
|
|
51
|
+
name: 'servicenow-xml-flow',
|
|
52
|
+
version: '1.0.0',
|
|
53
|
+
description: 'XML-first flow generation for ServiceNow - bypasses API issues'
|
|
54
|
+
});
|
|
55
|
+
this.nlMapper = new natural_language_mapper_1.NaturalLanguageFlowMapper();
|
|
56
|
+
}
|
|
57
|
+
setupTools() {
|
|
58
|
+
// Generate complete flow XML
|
|
59
|
+
this.registerTool({
|
|
60
|
+
name: 'snow_xml_flow_generate',
|
|
61
|
+
description: 'Generate complete Update Set XML for a flow that can be imported directly into ServiceNow',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {
|
|
65
|
+
name: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Flow name'
|
|
68
|
+
},
|
|
69
|
+
description: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
description: 'Flow description'
|
|
72
|
+
},
|
|
73
|
+
table: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'Table to trigger on (e.g., incident, sc_request)'
|
|
76
|
+
},
|
|
77
|
+
trigger_type: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
enum: ['record_created', 'record_updated', 'manual', 'scheduled'],
|
|
80
|
+
description: 'Trigger type'
|
|
81
|
+
},
|
|
82
|
+
trigger_condition: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Trigger condition (encoded query)'
|
|
85
|
+
},
|
|
86
|
+
activities: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
description: 'Flow activities',
|
|
89
|
+
items: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
name: { type: 'string' },
|
|
93
|
+
type: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
enum: ['notification', 'approval', 'script', 'create_record', 'update_record', 'rest_step']
|
|
96
|
+
},
|
|
97
|
+
order: { type: 'number' },
|
|
98
|
+
inputs: { type: 'object' },
|
|
99
|
+
outputs: { type: 'object' },
|
|
100
|
+
condition: { type: 'string' }
|
|
101
|
+
},
|
|
102
|
+
required: ['name', 'type', 'inputs']
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
update_set_name: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Name for the Update Set (optional)'
|
|
108
|
+
},
|
|
109
|
+
save_to_file: {
|
|
110
|
+
type: 'boolean',
|
|
111
|
+
default: true,
|
|
112
|
+
description: 'Save XML to file'
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
required: ['name', 'description', 'trigger_type', 'activities']
|
|
116
|
+
}
|
|
117
|
+
}, this.generateFlowXML.bind(this));
|
|
118
|
+
// Generate flow XML from natural language
|
|
119
|
+
this.registerTool({
|
|
120
|
+
name: 'snow_xml_flow_from_instruction',
|
|
121
|
+
description: 'Generate flow Update Set XML from natural language instruction',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
instruction: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Natural language description of the flow (e.g., "create approval flow for iPhone requests")'
|
|
128
|
+
},
|
|
129
|
+
save_to_file: {
|
|
130
|
+
type: 'boolean',
|
|
131
|
+
default: true,
|
|
132
|
+
description: 'Save XML to file'
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
required: ['instruction']
|
|
136
|
+
}
|
|
137
|
+
}, this.generateFlowFromInstruction.bind(this));
|
|
138
|
+
// Generate example flows
|
|
139
|
+
this.registerTool({
|
|
140
|
+
name: 'snow_xml_flow_examples',
|
|
141
|
+
description: 'Generate example flow XML files with common patterns',
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
example_type: {
|
|
146
|
+
type: 'string',
|
|
147
|
+
enum: ['approval', 'incident_notification', 'equipment_provisioning', 'data_processing', 'user_onboarding'],
|
|
148
|
+
description: 'Type of example flow to generate'
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
required: ['example_type']
|
|
152
|
+
}
|
|
153
|
+
}, this.generateExampleFlow.bind(this));
|
|
154
|
+
// List generated XML files
|
|
155
|
+
this.registerTool({
|
|
156
|
+
name: 'snow_xml_flow_list',
|
|
157
|
+
description: 'List all generated flow XML files',
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: 'object',
|
|
160
|
+
properties: {}
|
|
161
|
+
}
|
|
162
|
+
}, this.listGeneratedFiles.bind(this));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate flow XML from definition
|
|
166
|
+
*/
|
|
167
|
+
async generateFlowXML(args) {
|
|
168
|
+
try {
|
|
169
|
+
const generator = new xml_first_flow_generator_1.default(args.update_set_name);
|
|
170
|
+
const flowDef = {
|
|
171
|
+
name: args.name,
|
|
172
|
+
description: args.description,
|
|
173
|
+
table: args.table,
|
|
174
|
+
trigger_type: args.trigger_type,
|
|
175
|
+
trigger_condition: args.trigger_condition,
|
|
176
|
+
activities: args.activities.map((act, index) => ({
|
|
177
|
+
...act,
|
|
178
|
+
order: act.order || (index + 1) * 100
|
|
179
|
+
}))
|
|
180
|
+
};
|
|
181
|
+
const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
|
|
182
|
+
return {
|
|
183
|
+
success: true,
|
|
184
|
+
xml: args.save_to_file === false ? result.xml : undefined,
|
|
185
|
+
file_path: result.filePath,
|
|
186
|
+
message: `Generated PRODUCTION-READY Update Set XML for flow: ${args.name}`,
|
|
187
|
+
import_instructions: result.instructions,
|
|
188
|
+
flow_structure: {
|
|
189
|
+
flow_sys_id: generator.flowSysId,
|
|
190
|
+
activities_count: flowDef.activities.length,
|
|
191
|
+
trigger_type: flowDef.trigger_type,
|
|
192
|
+
table: flowDef.table || 'none'
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
success: false,
|
|
199
|
+
error: error instanceof Error ? error.message : String(error)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Generate flow from natural language instruction
|
|
205
|
+
*/
|
|
206
|
+
async generateFlowFromInstruction(args) {
|
|
207
|
+
try {
|
|
208
|
+
const { instruction } = args;
|
|
209
|
+
// Parse natural language to flow components
|
|
210
|
+
const flowRequirements = await this.nlMapper.parseFlowRequirements(instruction);
|
|
211
|
+
// Convert to XML flow definition
|
|
212
|
+
const flowDef = {
|
|
213
|
+
name: flowRequirements.name || `Flow ${Date.now()}`,
|
|
214
|
+
description: flowRequirements.description || instruction,
|
|
215
|
+
table: flowRequirements.tables?.[0] || 'incident',
|
|
216
|
+
trigger_type: this.mapTriggerType(flowRequirements.trigger_type || 'manual'),
|
|
217
|
+
trigger_condition: flowRequirements.trigger_condition || '',
|
|
218
|
+
activities: this.convertToXMLActivities(flowRequirements)
|
|
219
|
+
};
|
|
220
|
+
const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
|
|
221
|
+
return {
|
|
222
|
+
success: true,
|
|
223
|
+
xml: args.save_to_file === false ? result.xml : undefined,
|
|
224
|
+
file_path: result.filePath,
|
|
225
|
+
flow_definition: flowDef,
|
|
226
|
+
message: `Generated PRODUCTION flow XML from instruction: ${instruction}`,
|
|
227
|
+
import_instructions: result.instructions
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return {
|
|
232
|
+
success: false,
|
|
233
|
+
error: error instanceof Error ? error.message : String(error)
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Generate example flows
|
|
239
|
+
*/
|
|
240
|
+
async generateExampleFlow(args) {
|
|
241
|
+
try {
|
|
242
|
+
const { example_type } = args;
|
|
243
|
+
let flowDef;
|
|
244
|
+
switch (example_type) {
|
|
245
|
+
case 'approval':
|
|
246
|
+
flowDef = xml_first_flow_generator_1.default.createRealWorldExample(); // Use real-world example
|
|
247
|
+
break;
|
|
248
|
+
case 'incident_notification':
|
|
249
|
+
flowDef = this.getIncidentNotificationExample();
|
|
250
|
+
break;
|
|
251
|
+
case 'equipment_provisioning':
|
|
252
|
+
flowDef = this.getEquipmentProvisioningExample();
|
|
253
|
+
break;
|
|
254
|
+
case 'data_processing':
|
|
255
|
+
flowDef = this.getDataProcessingExample();
|
|
256
|
+
break;
|
|
257
|
+
case 'user_onboarding':
|
|
258
|
+
flowDef = this.getUserOnboardingExample();
|
|
259
|
+
break;
|
|
260
|
+
default:
|
|
261
|
+
throw new Error(`Unknown example type: ${example_type}`);
|
|
262
|
+
}
|
|
263
|
+
const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
xml: result.xml,
|
|
267
|
+
file_path: result.filePath,
|
|
268
|
+
flow_definition: flowDef,
|
|
269
|
+
message: `Generated REAL example ${example_type} flow (NO placeholders!)`,
|
|
270
|
+
import_instructions: result.instructions,
|
|
271
|
+
warning: 'This is a PRODUCTION-READY flow with real ServiceNow action IDs - ready for import!'
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
return {
|
|
276
|
+
success: false,
|
|
277
|
+
error: error instanceof Error ? error.message : String(error)
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* List generated XML files
|
|
283
|
+
*/
|
|
284
|
+
async listGeneratedFiles(args) {
|
|
285
|
+
try {
|
|
286
|
+
const outputDir = path.join(process.cwd(), 'flow-update-sets');
|
|
287
|
+
if (!fs.existsSync(outputDir)) {
|
|
288
|
+
return {
|
|
289
|
+
success: true,
|
|
290
|
+
files: [],
|
|
291
|
+
message: 'No flow XML files generated yet'
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const files = fs.readdirSync(outputDir)
|
|
295
|
+
.filter(file => file.endsWith('.xml'))
|
|
296
|
+
.map(file => {
|
|
297
|
+
const filePath = path.join(outputDir, file);
|
|
298
|
+
const stats = fs.statSync(filePath);
|
|
299
|
+
return {
|
|
300
|
+
name: file,
|
|
301
|
+
path: filePath,
|
|
302
|
+
size: stats.size,
|
|
303
|
+
created: stats.birthtime,
|
|
304
|
+
modified: stats.mtime
|
|
305
|
+
};
|
|
306
|
+
})
|
|
307
|
+
.sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
308
|
+
return {
|
|
309
|
+
success: true,
|
|
310
|
+
files: files,
|
|
311
|
+
count: files.length,
|
|
312
|
+
directory: outputDir,
|
|
313
|
+
message: `Found ${files.length} flow XML files`
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
return {
|
|
318
|
+
success: false,
|
|
319
|
+
error: error instanceof Error ? error.message : String(error)
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Helper methods for examples
|
|
325
|
+
*/
|
|
326
|
+
getApprovalFlowExample() {
|
|
327
|
+
return {
|
|
328
|
+
name: 'Multi-Level Approval Flow',
|
|
329
|
+
description: 'Production-ready multi-level approval workflow',
|
|
330
|
+
internal_name: 'multi_level_approval',
|
|
331
|
+
table: 'sc_request',
|
|
332
|
+
trigger_type: 'record_created',
|
|
333
|
+
trigger_condition: 'approval=requested',
|
|
334
|
+
run_as: 'user',
|
|
335
|
+
activities: [
|
|
336
|
+
{
|
|
337
|
+
name: 'Manager Approval',
|
|
338
|
+
type: 'approval',
|
|
339
|
+
order: 100,
|
|
340
|
+
inputs: {
|
|
341
|
+
table: 'sc_request',
|
|
342
|
+
record: '{{trigger.current.sys_id}}',
|
|
343
|
+
approver: '{{trigger.current.requested_for.manager}}',
|
|
344
|
+
approval_field: 'approval',
|
|
345
|
+
message: 'Please approve request {{trigger.current.number}} for {{trigger.current.requested_for.name}}'
|
|
346
|
+
},
|
|
347
|
+
outputs: {
|
|
348
|
+
state: 'string',
|
|
349
|
+
approver_sys_id: 'string'
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: 'Director Approval',
|
|
354
|
+
type: 'approval',
|
|
355
|
+
order: 200,
|
|
356
|
+
condition: '{{manager_approval.state}} == "approved" && {{trigger.current.price}} > 5000',
|
|
357
|
+
inputs: {
|
|
358
|
+
table: 'sc_request',
|
|
359
|
+
record: '{{trigger.current.sys_id}}',
|
|
360
|
+
approver: '{{trigger.current.requested_for.manager.manager}}',
|
|
361
|
+
approval_field: 'approval',
|
|
362
|
+
message: 'High-value request requires director approval: {{trigger.current.number}}'
|
|
363
|
+
},
|
|
364
|
+
outputs: {
|
|
365
|
+
state: 'string',
|
|
366
|
+
approver_sys_id: 'string'
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: 'Send Result Notification',
|
|
371
|
+
type: 'notification',
|
|
372
|
+
order: 300,
|
|
373
|
+
inputs: {
|
|
374
|
+
notification_id: (0, servicenow_id_generator_js_1.getNotificationTemplateSysId)('generic_notification'),
|
|
375
|
+
recipients: '{{trigger.current.requested_for}}',
|
|
376
|
+
values: {
|
|
377
|
+
request_number: '{{trigger.current.number}}',
|
|
378
|
+
final_status: '{{director_approval.state || manager_approval.state}}'
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
outputs: {
|
|
382
|
+
sent: 'boolean'
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
getIncidentNotificationExample() {
|
|
389
|
+
return {
|
|
390
|
+
name: 'High Priority Incident Notification',
|
|
391
|
+
description: 'Notifies management of high priority incidents',
|
|
392
|
+
table: 'incident',
|
|
393
|
+
trigger_type: 'record_created',
|
|
394
|
+
trigger_condition: 'priority<=2',
|
|
395
|
+
activities: [
|
|
396
|
+
{
|
|
397
|
+
name: 'Check Business Hours',
|
|
398
|
+
type: 'script',
|
|
399
|
+
order: 100,
|
|
400
|
+
inputs: {
|
|
401
|
+
script: `
|
|
402
|
+
var isBusinessHours = gs.isBusinessHours();
|
|
403
|
+
current.u_notified_outside_hours = !isBusinessHours;
|
|
404
|
+
return { is_business_hours: isBusinessHours };
|
|
405
|
+
`.trim()
|
|
406
|
+
},
|
|
407
|
+
outputs: {
|
|
408
|
+
is_business_hours: 'boolean'
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
name: 'Send Management Alert',
|
|
413
|
+
type: 'notification',
|
|
414
|
+
order: 200,
|
|
415
|
+
inputs: {
|
|
416
|
+
recipient: 'it-management@company.com',
|
|
417
|
+
subject: 'URGENT: P${current.priority} Incident Created',
|
|
418
|
+
message: 'High priority incident ${current.number} requires attention'
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: 'Create War Room Task',
|
|
423
|
+
type: 'create_record',
|
|
424
|
+
order: 300,
|
|
425
|
+
condition: '${current.priority} == 1',
|
|
426
|
+
inputs: {
|
|
427
|
+
table: 'task',
|
|
428
|
+
fields: {
|
|
429
|
+
short_description: 'War Room: ${current.number}',
|
|
430
|
+
description: 'Coordinate response for critical incident',
|
|
431
|
+
assigned_to: '${current.assignment_group.manager}'
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
getEquipmentProvisioningExample() {
|
|
439
|
+
return {
|
|
440
|
+
name: 'IT Equipment Provisioning',
|
|
441
|
+
description: 'Automated provisioning of IT equipment',
|
|
442
|
+
table: 'sc_request',
|
|
443
|
+
trigger_type: 'record_updated',
|
|
444
|
+
trigger_condition: 'state=approved^cat_item.category=hardware',
|
|
445
|
+
activities: [
|
|
446
|
+
{
|
|
447
|
+
name: 'Check Inventory',
|
|
448
|
+
type: 'rest_step',
|
|
449
|
+
order: 100,
|
|
450
|
+
inputs: {
|
|
451
|
+
endpoint: '${system.property.inventory_api_url}/check',
|
|
452
|
+
method: 'POST',
|
|
453
|
+
headers: {
|
|
454
|
+
'Content-Type': 'application/json',
|
|
455
|
+
'Authorization': 'Bearer ${system.property.inventory_api_token}'
|
|
456
|
+
},
|
|
457
|
+
body: {
|
|
458
|
+
item_code: '${current.cat_item.model_number}',
|
|
459
|
+
quantity: '${current.quantity}'
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
outputs: {
|
|
463
|
+
in_stock: 'boolean',
|
|
464
|
+
available_quantity: 'integer'
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: 'Create Asset Record',
|
|
469
|
+
type: 'create_record',
|
|
470
|
+
order: 200,
|
|
471
|
+
condition: '${check_inventory.in_stock} == true',
|
|
472
|
+
inputs: {
|
|
473
|
+
table: 'alm_asset',
|
|
474
|
+
fields: {
|
|
475
|
+
display_name: '${current.cat_item.name} - ${current.requested_for.name}',
|
|
476
|
+
assigned_to: '${current.requested_for}',
|
|
477
|
+
state: 'In use',
|
|
478
|
+
po_number: '${current.number}'
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: 'Send Delivery Instructions',
|
|
484
|
+
type: 'notification',
|
|
485
|
+
order: 300,
|
|
486
|
+
inputs: {
|
|
487
|
+
recipient: '${current.requested_for.email}',
|
|
488
|
+
subject: 'Equipment Ready for Pickup',
|
|
489
|
+
message: 'Your ${current.cat_item.name} is ready. Pickup location: ${pickup_location}'
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
getDataProcessingExample() {
|
|
496
|
+
return {
|
|
497
|
+
name: 'Daily Data Processing',
|
|
498
|
+
description: 'Process and analyze daily operational data',
|
|
499
|
+
trigger_type: 'scheduled',
|
|
500
|
+
trigger_condition: '0 2 * * *', // 2 AM daily
|
|
501
|
+
activities: [
|
|
502
|
+
{
|
|
503
|
+
name: 'Extract Yesterday Data',
|
|
504
|
+
type: 'script',
|
|
505
|
+
order: 100,
|
|
506
|
+
inputs: {
|
|
507
|
+
script: `
|
|
508
|
+
var yesterday = new GlideDateTime();
|
|
509
|
+
yesterday.addDays(-1);
|
|
510
|
+
var gr = new GlideRecord('incident');
|
|
511
|
+
gr.addQuery('opened_at', '>=', yesterday.getDate());
|
|
512
|
+
gr.query();
|
|
513
|
+
var count = gr.getRowCount();
|
|
514
|
+
return { record_count: count, date: yesterday.getDate() };
|
|
515
|
+
`.trim()
|
|
516
|
+
},
|
|
517
|
+
outputs: {
|
|
518
|
+
record_count: 'integer',
|
|
519
|
+
date: 'string'
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: 'Generate Report',
|
|
524
|
+
type: 'script',
|
|
525
|
+
order: 200,
|
|
526
|
+
inputs: {
|
|
527
|
+
script: `
|
|
528
|
+
// Generate daily report logic
|
|
529
|
+
var report = generateDailyReport(current.record_count);
|
|
530
|
+
return { report_id: report.sys_id };
|
|
531
|
+
`.trim()
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: 'Send Report',
|
|
536
|
+
type: 'notification',
|
|
537
|
+
order: 300,
|
|
538
|
+
inputs: {
|
|
539
|
+
recipient: 'operations@company.com',
|
|
540
|
+
subject: 'Daily Operations Report - ${date}',
|
|
541
|
+
message: 'Daily report is ready. ${record_count} incidents processed.',
|
|
542
|
+
attachments: '${report_id}'
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
getUserOnboardingExample() {
|
|
549
|
+
return {
|
|
550
|
+
name: 'Employee Onboarding Workflow',
|
|
551
|
+
description: 'Automated onboarding process for new employees',
|
|
552
|
+
table: 'sys_user',
|
|
553
|
+
trigger_type: 'record_created',
|
|
554
|
+
trigger_condition: 'employee_number!=NULL',
|
|
555
|
+
activities: [
|
|
556
|
+
{
|
|
557
|
+
name: 'Create AD Account',
|
|
558
|
+
type: 'rest_step',
|
|
559
|
+
order: 100,
|
|
560
|
+
inputs: {
|
|
561
|
+
endpoint: '${system.property.ad_api_url}/users',
|
|
562
|
+
method: 'POST',
|
|
563
|
+
body: {
|
|
564
|
+
username: '${current.user_name}',
|
|
565
|
+
email: '${current.email}',
|
|
566
|
+
department: '${current.department}'
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: 'Assign Equipment',
|
|
572
|
+
type: 'create_record',
|
|
573
|
+
order: 200,
|
|
574
|
+
inputs: {
|
|
575
|
+
table: 'sc_request',
|
|
576
|
+
fields: {
|
|
577
|
+
requested_for: '${current.sys_id}',
|
|
578
|
+
cat_item: '${system.property.standard_laptop_item}',
|
|
579
|
+
short_description: 'New Employee Equipment - ${current.name}'
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: 'Schedule Training',
|
|
585
|
+
type: 'create_record',
|
|
586
|
+
order: 300,
|
|
587
|
+
inputs: {
|
|
588
|
+
table: 'task',
|
|
589
|
+
fields: {
|
|
590
|
+
short_description: 'Onboarding Training - ${current.name}',
|
|
591
|
+
assigned_to: '${current.department.training_coordinator}',
|
|
592
|
+
due_date: '+7 days'
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
name: 'Send Welcome Email',
|
|
598
|
+
type: 'notification',
|
|
599
|
+
order: 400,
|
|
600
|
+
inputs: {
|
|
601
|
+
recipient: '${current.email}',
|
|
602
|
+
cc: '${current.manager.email}',
|
|
603
|
+
subject: 'Welcome to the Team!',
|
|
604
|
+
message: 'Welcome ${current.first_name}! Your accounts are being set up.'
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Helper methods
|
|
612
|
+
*/
|
|
613
|
+
mapTriggerType(type) {
|
|
614
|
+
const typeMap = {
|
|
615
|
+
'create': 'record_created',
|
|
616
|
+
'update': 'record_updated',
|
|
617
|
+
'manual': 'manual',
|
|
618
|
+
'scheduled': 'scheduled',
|
|
619
|
+
'cron': 'scheduled'
|
|
620
|
+
};
|
|
621
|
+
return typeMap[type.toLowerCase()] || 'manual';
|
|
622
|
+
}
|
|
623
|
+
convertToXMLActivities(requirements) {
|
|
624
|
+
const activities = [];
|
|
625
|
+
// Convert actions to activities
|
|
626
|
+
if (requirements.actions && Array.isArray(requirements.actions)) {
|
|
627
|
+
requirements.actions.forEach((action, index) => {
|
|
628
|
+
activities.push({
|
|
629
|
+
name: action.name || `Activity ${index + 1}`,
|
|
630
|
+
type: this.mapActionType(action.type || 'script'),
|
|
631
|
+
order: (index + 1) * 100,
|
|
632
|
+
inputs: action.config || action.inputs || {},
|
|
633
|
+
outputs: action.outputs,
|
|
634
|
+
condition: action.condition
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
// If no activities but has requirements, generate default activities
|
|
639
|
+
if (activities.length === 0 && requirements.description) {
|
|
640
|
+
activities.push({
|
|
641
|
+
name: 'Process Request',
|
|
642
|
+
type: 'script',
|
|
643
|
+
order: 100,
|
|
644
|
+
inputs: {
|
|
645
|
+
script: '// Process logic here\ngs.info("Processing: " + current.number);'
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
return activities;
|
|
650
|
+
}
|
|
651
|
+
mapActionType(type) {
|
|
652
|
+
const typeMap = {
|
|
653
|
+
'email': 'notification',
|
|
654
|
+
'notify': 'notification',
|
|
655
|
+
'approve': 'approval',
|
|
656
|
+
'script': 'script',
|
|
657
|
+
'create': 'create_record',
|
|
658
|
+
'update': 'update_record',
|
|
659
|
+
'rest': 'rest_step',
|
|
660
|
+
'api': 'rest_step'
|
|
661
|
+
};
|
|
662
|
+
return typeMap[type.toLowerCase()] || 'script';
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
exports.ServiceNowXMLFlowMCP = ServiceNowXMLFlowMCP;
|
|
666
|
+
// Start the server
|
|
667
|
+
const server = new ServiceNowXMLFlowMCP();
|
|
668
|
+
server.start().catch(error => {
|
|
669
|
+
console.error('Failed to start XML Flow MCP server:', error);
|
|
670
|
+
process.exit(1);
|
|
671
|
+
});
|