snow-flow 1.2.3 → 1.3.0

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.
@@ -66,10 +66,12 @@ class BaseMCPServer {
66
66
  let metrics = this.toolMetrics.get(name) || { calls: 0, totalTime: 0, errors: 0 };
67
67
  metrics.calls++;
68
68
  try {
69
- // Validate authentication first
70
- const authResult = await this.validateAuth();
71
- if (!authResult.success) {
72
- throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Authentication failed: ${authResult.error}`);
69
+ // Validate authentication first (skip if not required)
70
+ if (this.config.requiresAuth !== false) {
71
+ const authResult = await this.validateAuth();
72
+ if (!authResult.success) {
73
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Authentication failed: ${authResult.error}`);
74
+ }
73
75
  }
74
76
  // Execute tool with retry logic
75
77
  const result = await this.executeWithRetry(name, args);
@@ -91,6 +93,10 @@ class BaseMCPServer {
91
93
  * Setup authentication with automatic token refresh
92
94
  */
93
95
  setupAuthentication() {
96
+ // Skip authentication setup if not required
97
+ if (this.config.requiresAuth === false) {
98
+ return;
99
+ }
94
100
  // Check auth every 5 minutes
95
101
  this.authCheckInterval = setInterval(async () => {
96
102
  try {
@@ -305,10 +311,12 @@ class BaseMCPServer {
305
311
  */
306
312
  async start() {
307
313
  this.logger.info(`Starting ${this.config.name} v${this.config.version}`);
308
- // Validate initial connection
309
- const authResult = await this.validateAuth();
310
- if (!authResult.success) {
311
- this.logger.warn('Starting without authentication - some features may be limited');
314
+ // Validate initial connection (skip if not required)
315
+ if (this.config.requiresAuth !== false) {
316
+ const authResult = await this.validateAuth();
317
+ if (!authResult.success) {
318
+ this.logger.warn('Starting without authentication - some features may be limited');
319
+ }
312
320
  }
313
321
  await this.server.connect(this.transport);
314
322
  this.logger.info('MCP server started successfully');
@@ -2258,6 +2258,384 @@ Run snow_deployment_debug for basic session info or check the logs for more deta
2258
2258
  }
2259
2259
  return result;
2260
2260
  }
2261
+ /**
2262
+ * Generate Update Set XML based on artifact type
2263
+ */
2264
+ async generateUpdateSetXML(type, config, updateSetSession) {
2265
+ switch (type) {
2266
+ case 'widget':
2267
+ return this.generateWidgetUpdateSetXML(config);
2268
+ case 'flow':
2269
+ return this.generateFlowUpdateSetXML(config);
2270
+ case 'application':
2271
+ return this.generateApplicationUpdateSetXML(config);
2272
+ default:
2273
+ throw new Error(`Update Set XML generation not implemented for type: ${type}`);
2274
+ }
2275
+ }
2276
+ /**
2277
+ * Generate Update Set XML for Flow Designer flows
2278
+ */
2279
+ generateFlowUpdateSetXML(args) {
2280
+ const timestamp = new Date().toISOString();
2281
+ const updateSetName = `Flow_${args.name}_${Date.now()}`;
2282
+ // Generate unique identifiers
2283
+ const updateSetId = this.generateGUID();
2284
+ const flowId = this.generateGUID();
2285
+ const triggerId = this.generateGUID();
2286
+ const updateXmlId = this.generateGUID();
2287
+ // Parse flow definition if it's a string
2288
+ let flowDefinition = args.flow_definition;
2289
+ if (typeof flowDefinition === 'string') {
2290
+ try {
2291
+ flowDefinition = JSON.parse(flowDefinition);
2292
+ }
2293
+ catch (e) {
2294
+ flowDefinition = { activities: [] };
2295
+ }
2296
+ }
2297
+ // Ensure flow definition has proper structure
2298
+ if (!flowDefinition || typeof flowDefinition !== 'object') {
2299
+ flowDefinition = { activities: [] };
2300
+ }
2301
+ // Generate action instances and flow logic
2302
+ const { actionInstances, flowLogics, completeFlowDefinition } = this.generateFlowComponents(flowDefinition, flowId, triggerId, timestamp);
2303
+ // Calculate total update count
2304
+ const totalUpdates = 1 + actionInstances.length + flowLogics.length + 1; // flow + actions + logics + trigger
2305
+ const xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
2306
+ <unload unload_date="${timestamp}">
2307
+ <sys_update_set action="INSERT_OR_UPDATE">
2308
+ <application display_value="Global">global</application>
2309
+ <category>customer</category>
2310
+ <description>Auto-generated Update Set for Flow Designer: ${args.name}</description>
2311
+ <is_default>false</is_default>
2312
+ <name>${updateSetName}</name>
2313
+ <origin_sys_id/>
2314
+ <release_date/>
2315
+ <state>complete</state>
2316
+ <sys_created_by>snow-flow</sys_created_by>
2317
+ <sys_created_on>${timestamp}</sys_created_on>
2318
+ <sys_id>${updateSetId}</sys_id>
2319
+ <sys_mod_count>0</sys_mod_count>
2320
+ <sys_updated_by>snow-flow</sys_updated_by>
2321
+ <sys_updated_on>${timestamp}</sys_updated_on>
2322
+ <update_count>${totalUpdates}</update_count>
2323
+ </sys_update_set>
2324
+
2325
+ <!-- Main Flow Record -->
2326
+ <sys_update_xml action="INSERT_OR_UPDATE">
2327
+ <action>INSERT_OR_UPDATE</action>
2328
+ <application display_value="Global">global</application>
2329
+ <category>customer</category>
2330
+ <comments/>
2331
+ <name>sys_hub_flow_${flowId}</name>
2332
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2333
+ <record_update table="sys_hub_flow">
2334
+ <sys_hub_flow action="INSERT_OR_UPDATE">
2335
+ <access>public</access>
2336
+ <acls/>
2337
+ <active>${args.active !== false ? 'true' : 'false'}</active>
2338
+ <annotation/>
2339
+ <callable_by_client_api>false</callable_by_client_api>
2340
+ <category>${args.category || 'automation'}</category>
2341
+ <checked_out_by/>
2342
+ <compiler_build/>
2343
+ <copied_from/>
2344
+ <copied_from_name/>
2345
+ <description>${args.description || ''}</description>
2346
+ <internal_name>global.${args.name}</internal_name>
2347
+ <label_cache>[{"name":"${args.name}","internal_name":"${args.name}","label":"${args.name}","description":"${args.description || ''}","language":"en","source":""}]</label_cache>
2348
+ <latest_snapshot/>
2349
+ <master_snapshot><![CDATA[${JSON.stringify(completeFlowDefinition)}]]></master_snapshot>
2350
+ <name>${args.name}</name>
2351
+ <natlang/>
2352
+ <outputs_cache>[]</outputs_cache>
2353
+ <remote_trigger_id/>
2354
+ <run_as>user</run_as>
2355
+ <run_as_tz/>
2356
+ <sc_callable>false</sc_callable>
2357
+ <show_draft_actions>false</show_draft_actions>
2358
+ <show_triggered_flows>false</show_triggered_flows>
2359
+ <status>published</status>
2360
+ <sys_class_name>sys_hub_flow</sys_class_name>
2361
+ <sys_created_by>snow-flow</sys_created_by>
2362
+ <sys_created_on>${timestamp}</sys_created_on>
2363
+ <sys_domain>global</sys_domain>
2364
+ <sys_domain_path>/</sys_domain_path>
2365
+ <sys_id>${flowId}</sys_id>
2366
+ <sys_mod_count>0</sys_mod_count>
2367
+ <sys_name>${args.name}</sys_name>
2368
+ <sys_overrides/>
2369
+ <sys_package display_value="Global" source="global">global</sys_package>
2370
+ <sys_policy/>
2371
+ <sys_scope display_value="Global">global</sys_scope>
2372
+ <sys_update_name>sys_hub_flow_${flowId}</sys_update_name>
2373
+ <sys_updated_by>snow-flow</sys_updated_by>
2374
+ <sys_updated_on>${timestamp}</sys_updated_on>
2375
+ <type>${args.flow_type || 'flow'}</type>
2376
+ </sys_hub_flow>
2377
+ </record_update>]]></payload>
2378
+ <payload_hash>-1</payload_hash>
2379
+ <record_name>${args.name}</record_name>
2380
+ <reverted_from/>
2381
+ <source_table>sys_hub_flow</source_table>
2382
+ <state>current</state>
2383
+ <sys_created_by>snow-flow</sys_created_by>
2384
+ <sys_created_on>${timestamp}</sys_created_on>
2385
+ <sys_id>${updateXmlId}</sys_id>
2386
+ <sys_mod_count>0</sys_mod_count>
2387
+ <sys_updated_by>snow-flow</sys_updated_by>
2388
+ <sys_updated_on>${timestamp}</sys_updated_on>
2389
+ <table>sys_hub_flow</table>
2390
+ <target_name>${args.name}</target_name>
2391
+ <type>Flow Designer</type>
2392
+ <update_domain>global</update_domain>
2393
+ <update_set display_value="${updateSetName}">${updateSetId}</update_set>
2394
+ <view/>
2395
+ </sys_update_xml>
2396
+
2397
+ <!-- Trigger Instance -->
2398
+ ${this.generateTriggerInstanceXML(args, flowId, triggerId, timestamp, updateSetId, updateSetName)}
2399
+
2400
+ <!-- Action Instances -->
2401
+ ${actionInstances.map(instance => instance.xml).join('\n\n ')}
2402
+
2403
+ <!-- Flow Logic (Connections) -->
2404
+ ${flowLogics.map(logic => logic.xml).join('\n\n ')}
2405
+ </unload>`;
2406
+ return xmlContent;
2407
+ }
2408
+ /**
2409
+ * Generate flow components (actions, logic, complete definition)
2410
+ */
2411
+ generateFlowComponents(flowDefinition, flowId, triggerId, timestamp) {
2412
+ const actionInstances = [];
2413
+ const flowLogics = [];
2414
+ // Process activities/actions from flow definition
2415
+ const activities = flowDefinition.activities || flowDefinition.steps || [];
2416
+ const actionIds = [];
2417
+ // Generate action instances
2418
+ activities.forEach((activity, index) => {
2419
+ const actionId = this.generateGUID();
2420
+ actionIds.push(actionId);
2421
+ const actionXml = this.generateActionInstanceXML(activity, actionId, flowId, index, timestamp);
2422
+ actionInstances.push({ id: actionId, xml: actionXml });
2423
+ });
2424
+ // Generate flow logic (connections between actions)
2425
+ for (let i = 0; i < actionIds.length; i++) {
2426
+ const logicId = this.generateGUID();
2427
+ let fromId = i === 0 ? triggerId : actionIds[i - 1];
2428
+ let toId = actionIds[i];
2429
+ const logicXml = this.generateFlowLogicXML(logicId, flowId, fromId, toId, i, timestamp);
2430
+ flowLogics.push({ id: logicId, xml: logicXml });
2431
+ }
2432
+ // Create complete flow definition with all components
2433
+ const completeFlowDefinition = {
2434
+ trigger: {
2435
+ type: flowDefinition.trigger_type || "manual",
2436
+ table: flowDefinition.table || "incident",
2437
+ condition: flowDefinition.condition || "",
2438
+ sys_id: triggerId
2439
+ },
2440
+ actions: activities.map((activity, index) => ({
2441
+ ...activity,
2442
+ sys_id: actionIds[index],
2443
+ sequence: index + 1
2444
+ })),
2445
+ logic: flowLogics.map(logic => ({
2446
+ sys_id: logic.id,
2447
+ from: logic.id === flowLogics[0]?.id ? triggerId : actionIds[flowLogics.indexOf(logic) - 1],
2448
+ to: actionIds[flowLogics.indexOf(logic)]
2449
+ })),
2450
+ inputs: flowDefinition.inputs || [],
2451
+ outputs: flowDefinition.outputs || [],
2452
+ steps: activities
2453
+ };
2454
+ return { actionInstances, flowLogics, completeFlowDefinition };
2455
+ }
2456
+ /**
2457
+ * Generate trigger instance XML
2458
+ */
2459
+ generateTriggerInstanceXML(args, flowId, triggerId, timestamp, updateSetId, updateSetName) {
2460
+ const updateXmlId = this.generateGUID();
2461
+ return `<sys_update_xml action="INSERT_OR_UPDATE">
2462
+ <action>INSERT_OR_UPDATE</action>
2463
+ <application display_value="Global">global</application>
2464
+ <category>customer</category>
2465
+ <comments/>
2466
+ <name>sys_hub_trigger_instance_${triggerId}</name>
2467
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2468
+ <record_update table="sys_hub_trigger_instance">
2469
+ <sys_hub_trigger_instance action="INSERT_OR_UPDATE">
2470
+ <active>true</active>
2471
+ <condition>${args.condition || ''}</condition>
2472
+ <dynamic_ref_qual>false</dynamic_ref_qual>
2473
+ <flow display_value="${args.name}">${flowId}</flow>
2474
+ <order>100</order>
2475
+ <sys_class_name>sys_hub_trigger_instance</sys_class_name>
2476
+ <sys_created_by>snow-flow</sys_created_by>
2477
+ <sys_created_on>${timestamp}</sys_created_on>
2478
+ <sys_domain>global</sys_domain>
2479
+ <sys_domain_path>/</sys_domain_path>
2480
+ <sys_id>${triggerId}</sys_id>
2481
+ <sys_mod_count>0</sys_mod_count>
2482
+ <sys_name>${args.name} Trigger</sys_name>
2483
+ <sys_overrides/>
2484
+ <sys_package display_value="Global" source="global">global</sys_package>
2485
+ <sys_policy/>
2486
+ <sys_scope display_value="Global">global</sys_scope>
2487
+ <sys_update_name>sys_hub_trigger_instance_${triggerId}</sys_update_name>
2488
+ <sys_updated_by>snow-flow</sys_updated_by>
2489
+ <sys_updated_on>${timestamp}</sys_updated_on>
2490
+ <table>${args.table || 'incident'}</table>
2491
+ <trigger_type>${args.trigger_type || 'manual'}</trigger_type>
2492
+ </sys_hub_trigger_instance>
2493
+ </record_update>]]></payload>
2494
+ <payload_hash>-1</payload_hash>
2495
+ <record_name>${args.name} Trigger</record_name>
2496
+ <reverted_from/>
2497
+ <source_table>sys_hub_trigger_instance</source_table>
2498
+ <state>current</state>
2499
+ <sys_created_by>snow-flow</sys_created_by>
2500
+ <sys_created_on>${timestamp}</sys_created_on>
2501
+ <sys_id>${updateXmlId}</sys_id>
2502
+ <sys_mod_count>0</sys_mod_count>
2503
+ <sys_updated_by>snow-flow</sys_updated_by>
2504
+ <sys_updated_on>${timestamp}</sys_updated_on>
2505
+ <table>sys_hub_trigger_instance</table>
2506
+ <target_name>${args.name} Trigger</target_name>
2507
+ <type>Flow Designer</type>
2508
+ <update_domain>global</update_domain>
2509
+ <update_set display_value="${updateSetName}">${updateSetId}</update_set>
2510
+ <view/>
2511
+ </sys_update_xml>`;
2512
+ }
2513
+ /**
2514
+ * Generate action instance XML
2515
+ */
2516
+ generateActionInstanceXML(activity, actionId, flowId, sequence, timestamp) {
2517
+ const updateXmlId = this.generateGUID();
2518
+ return `<sys_update_xml action="INSERT_OR_UPDATE">
2519
+ <action>INSERT_OR_UPDATE</action>
2520
+ <application display_value="Global">global</application>
2521
+ <category>customer</category>
2522
+ <comments/>
2523
+ <name>sys_hub_action_instance_${actionId}</name>
2524
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2525
+ <record_update table="sys_hub_action_instance">
2526
+ <sys_hub_action_instance action="INSERT_OR_UPDATE">
2527
+ <action>${activity.action || activity.type || 'script'}</action>
2528
+ <action_name>${activity.name || `Step ${sequence + 1}`}</action_name>
2529
+ <active>true</active>
2530
+ <anchor_x>${activity.x || (200 + sequence * 150)}</anchor_x>
2531
+ <anchor_y>${activity.y || 200}</anchor_y>
2532
+ <flow display_value="Flow">${flowId}</flow>
2533
+ <inputs>${JSON.stringify(activity.inputs || {})}</inputs>
2534
+ <order>${(sequence + 1) * 100}</order>
2535
+ <outputs>${JSON.stringify(activity.outputs || {})}</outputs>
2536
+ <script>${activity.script || activity.code || ''}</script>
2537
+ <sys_class_name>sys_hub_action_instance</sys_class_name>
2538
+ <sys_created_by>snow-flow</sys_created_by>
2539
+ <sys_created_on>${timestamp}</sys_created_on>
2540
+ <sys_domain>global</sys_domain>
2541
+ <sys_domain_path>/</sys_domain_path>
2542
+ <sys_id>${actionId}</sys_id>
2543
+ <sys_mod_count>0</sys_mod_count>
2544
+ <sys_name>${activity.name || `Step ${sequence + 1}`}</sys_name>
2545
+ <sys_overrides/>
2546
+ <sys_package display_value="Global" source="global">global</sys_package>
2547
+ <sys_policy/>
2548
+ <sys_scope display_value="Global">global</sys_scope>
2549
+ <sys_update_name>sys_hub_action_instance_${actionId}</sys_update_name>
2550
+ <sys_updated_by>snow-flow</sys_updated_by>
2551
+ <sys_updated_on>${timestamp}</sys_updated_on>
2552
+ </sys_hub_action_instance>
2553
+ </record_update>]]></payload>
2554
+ <payload_hash>-1</payload_hash>
2555
+ <record_name>${activity.name || `Step ${sequence + 1}`}</record_name>
2556
+ <reverted_from/>
2557
+ <source_table>sys_hub_action_instance</source_table>
2558
+ <state>current</state>
2559
+ <sys_created_by>snow-flow</sys_created_by>
2560
+ <sys_created_on>${timestamp}</sys_created_on>
2561
+ <sys_id>${updateXmlId}</sys_id>
2562
+ <sys_mod_count>0</sys_mod_count>
2563
+ <sys_updated_by>snow-flow</sys_updated_by>
2564
+ <sys_updated_on>${timestamp}</sys_updated_on>
2565
+ <table>sys_hub_action_instance</table>
2566
+ <target_name>${activity.name || `Step ${sequence + 1}`}</target_name>
2567
+ <type>Flow Designer</type>
2568
+ <update_domain>global</update_domain>
2569
+ <update_set display_value="Flow Update Set">${flowId.substring(0, 8)}</update_set>
2570
+ <view/>
2571
+ </sys_update_xml>`;
2572
+ }
2573
+ /**
2574
+ * Generate flow logic XML (connections between actions)
2575
+ */
2576
+ generateFlowLogicXML(logicId, flowId, fromId, toId, sequence, timestamp) {
2577
+ const updateXmlId = this.generateGUID();
2578
+ return `<sys_update_xml action="INSERT_OR_UPDATE">
2579
+ <action>INSERT_OR_UPDATE</action>
2580
+ <application display_value="Global">global</application>
2581
+ <category>customer</category>
2582
+ <comments/>
2583
+ <name>sys_hub_flow_logic_${logicId}</name>
2584
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2585
+ <record_update table="sys_hub_flow_logic">
2586
+ <sys_hub_flow_logic action="INSERT_OR_UPDATE">
2587
+ <condition>true</condition>
2588
+ <flow display_value="Flow">${flowId}</flow>
2589
+ <from_step>${fromId}</from_step>
2590
+ <order>${(sequence + 1) * 10}</order>
2591
+ <relationship_type>success</relationship_type>
2592
+ <sys_class_name>sys_hub_flow_logic</sys_class_name>
2593
+ <sys_created_by>snow-flow</sys_created_by>
2594
+ <sys_created_on>${timestamp}</sys_created_on>
2595
+ <sys_domain>global</sys_domain>
2596
+ <sys_domain_path>/</sys_domain_path>
2597
+ <sys_id>${logicId}</sys_id>
2598
+ <sys_mod_count>0</sys_mod_count>
2599
+ <sys_name>Connection ${sequence + 1}</sys_name>
2600
+ <sys_overrides/>
2601
+ <sys_package display_value="Global" source="global">global</sys_package>
2602
+ <sys_policy/>
2603
+ <sys_scope display_value="Global">global</sys_scope>
2604
+ <sys_update_name>sys_hub_flow_logic_${logicId}</sys_update_name>
2605
+ <sys_updated_by>snow-flow</sys_updated_by>
2606
+ <sys_updated_on>${timestamp}</sys_updated_on>
2607
+ <to_step>${toId}</to_step>
2608
+ </sys_hub_flow_logic>
2609
+ </record_update>]]></payload>
2610
+ <payload_hash>-1</payload_hash>
2611
+ <record_name>Connection ${sequence + 1}</record_name>
2612
+ <reverted_from/>
2613
+ <source_table>sys_hub_flow_logic</source_table>
2614
+ <state>current</state>
2615
+ <sys_created_by>snow-flow</sys_created_by>
2616
+ <sys_created_on>${timestamp}</sys_created_on>
2617
+ <sys_id>${updateXmlId}</sys_id>
2618
+ <sys_mod_count>0</sys_mod_count>
2619
+ <sys_updated_by>snow-flow</sys_updated_by>
2620
+ <sys_updated_on>${timestamp}</sys_updated_on>
2621
+ <table>sys_hub_flow_logic</table>
2622
+ <target_name>Connection ${sequence + 1}</target_name>
2623
+ <type>Flow Designer</type>
2624
+ <update_domain>global</update_domain>
2625
+ <update_set display_value="Flow Update Set">${flowId.substring(0, 8)}</update_set>
2626
+ <view/>
2627
+ </sys_update_xml>`;
2628
+ }
2629
+ /**
2630
+ * Generate Update Set XML for applications (stub for now)
2631
+ */
2632
+ generateApplicationUpdateSetXML(args) {
2633
+ // TODO: Implement application XML generation
2634
+ return `<?xml version="1.0" encoding="UTF-8"?>
2635
+ <unload>
2636
+ <!-- Application Update Set XML not yet implemented -->
2637
+ </unload>`;
2638
+ }
2261
2639
  /**
2262
2640
  * Preview widget with test data
2263
2641
  */
@@ -11,6 +11,7 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
11
11
  const servicenow_client_js_1 = require("../utils/servicenow-client.js");
12
12
  const snow_oauth_js_1 = require("../utils/snow-oauth.js");
13
13
  const logger_js_1 = require("../utils/logger.js");
14
+ const flow_structure_builder_js_1 = require("../utils/flow-structure-builder.js");
14
15
  class ServiceNowFlowComposerMCP {
15
16
  constructor() {
16
17
  this.server = new index_js_1.Server({
@@ -300,8 +301,27 @@ class ServiceNowFlowComposerMCP {
300
301
  let deploymentResult = null;
301
302
  if (args.deploy_immediately !== false) {
302
303
  console.log('šŸš€ DEPLOYING intelligent flow to ServiceNow...');
303
- deploymentResult = await this.client.createFlow(flowDefinition);
304
- console.log('šŸš€ Deployment result:', deploymentResult);
304
+ // Use the conversion utility to ensure proper format
305
+ const enhancedFlowDefinition = (0, flow_structure_builder_js_1.convertToFlowDefinition)({
306
+ name: parsedIntent.flowName,
307
+ description: parsedIntent.description,
308
+ table: parsedIntent.table,
309
+ trigger: parsedIntent.trigger,
310
+ activities: flowDefinition.activities || [],
311
+ variables: flowDefinition.variables || [],
312
+ connections: flowDefinition.connections || [],
313
+ error_handling: flowDefinition.error_handling || []
314
+ });
315
+ // Try enhanced method first, fallback to original if needed
316
+ try {
317
+ deploymentResult = await this.client.createFlowWithStructureBuilder(enhancedFlowDefinition);
318
+ console.log('šŸš€ Enhanced deployment result:', deploymentResult);
319
+ }
320
+ catch (enhancedError) {
321
+ console.warn('āš ļø Enhanced deployment failed, falling back to original method:', enhancedError);
322
+ deploymentResult = await this.client.createFlow(flowDefinition);
323
+ console.log('šŸš€ Fallback deployment result:', deploymentResult);
324
+ }
305
325
  }
306
326
  const credentials = await this.oauth.loadCredentials();
307
327
  const flowUrl = `https://${credentials?.instance}/flow-designer/flow/${parsedIntent.flowName}`;
@@ -48,7 +48,8 @@ class ServiceNowMemoryMCP extends base_mcp_server_1.BaseMCPServer {
48
48
  const config = {
49
49
  name: 'servicenow-memory',
50
50
  version: '1.0.0',
51
- description: 'Memory and todo management for ServiceNow multi-agent coordination'
51
+ description: 'Memory and todo management for ServiceNow multi-agent coordination',
52
+ requiresAuth: false // Memory server doesn't need ServiceNow authentication
52
53
  };
53
54
  super(config);
54
55
  this.config = config;
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Test script for iPhone Request Approval Flow
5
+ * Demonstrates the complete integrated solution with all fixes
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.testIPhoneRequestApprovalFlow = testIPhoneRequestApprovalFlow;
9
+ const servicenow_client_1 = require("./utils/servicenow-client");
10
+ const flow_structure_builder_1 = require("./utils/flow-structure-builder");
11
+ async function testIPhoneRequestApprovalFlow() {
12
+ console.log('🧪 Testing iPhone Request Approval Flow Integration');
13
+ console.log('================================================');
14
+ try {
15
+ // Initialize ServiceNow client
16
+ const client = new servicenow_client_1.ServiceNowClient();
17
+ // Define the iPhone Request Approval flow
18
+ const iPhoneFlowDefinition = {
19
+ name: 'iPhone Request Approval',
20
+ description: 'Approval workflow for iPhone equipment requests with admin approval and requester notification',
21
+ table: 'sc_request',
22
+ trigger: {
23
+ type: 'record_created',
24
+ table: 'sc_request',
25
+ condition: 'request_itemCONTAINSiPhone^ORcatalogue_itemLIKEiPhone'
26
+ },
27
+ activities: [
28
+ {
29
+ id: 'approval_admin',
30
+ name: 'Admin Approval',
31
+ type: 'approval',
32
+ inputs: {
33
+ approver: 'admin',
34
+ approval_question: 'Approve iPhone request for ${trigger.requested_for.name}?',
35
+ instructions: 'Please review the iPhone request and approve or reject based on company policy.',
36
+ timeout: '7 days'
37
+ },
38
+ outputs: {
39
+ approval_decision: 'string',
40
+ approved_by: 'string',
41
+ approval_comments: 'string'
42
+ }
43
+ },
44
+ {
45
+ id: 'notify_requester',
46
+ name: 'Notify Requester',
47
+ type: 'notification',
48
+ inputs: {
49
+ recipient: '${trigger.requested_for.email}',
50
+ subject: 'iPhone Request ${approval_admin.approval_decision}',
51
+ message: `Dear ${trigger.requested_for.name},
52
+
53
+ Your iPhone request has been ${approval_admin.approval_decision}.
54
+
55
+ Request Details:
56
+ - Item: ${trigger.request_item.short_description}
57
+ - Requested: ${trigger.sys_created_on}
58
+ - Decision by: ${approval_admin.approved_by}
59
+ - Comments: ${approval_admin.approval_comments}
60
+
61
+ ${approval_admin.approval_decision === 'approved' ?
62
+ 'Your iPhone will be processed and delivered according to standard procedures.' :
63
+ 'Please contact your manager if you have questions about this decision.'}
64
+
65
+ Best regards,
66
+ IT Support Team`
67
+ },
68
+ condition: 'approval_admin.approval_decision != null'
69
+ }
70
+ ],
71
+ variables: [
72
+ {
73
+ name: 'approval_decision',
74
+ label: 'Approval Decision',
75
+ type: 'string',
76
+ required: false,
77
+ default: ''
78
+ },
79
+ {
80
+ name: 'requester_email',
81
+ label: 'Requester Email',
82
+ type: 'string',
83
+ required: true,
84
+ default: '${trigger.requested_for.email}'
85
+ }
86
+ ],
87
+ connections: [
88
+ {
89
+ from: 'trigger',
90
+ to: 'approval_admin',
91
+ condition: ''
92
+ },
93
+ {
94
+ from: 'approval_admin',
95
+ to: 'notify_requester',
96
+ condition: 'approval_admin.approval_decision != null'
97
+ }
98
+ ],
99
+ error_handling: []
100
+ };
101
+ console.log('āœ… Step 1: Flow definition created');
102
+ console.log(` - Name: ${iPhoneFlowDefinition.name}`);
103
+ console.log(` - Trigger: ${iPhoneFlowDefinition.trigger.type} on ${iPhoneFlowDefinition.trigger.table}`);
104
+ console.log(` - Activities: ${iPhoneFlowDefinition.activities.length}`);
105
+ console.log(` - Variables: ${iPhoneFlowDefinition.variables.length}`);
106
+ // Test 1: Create complete flow components using enhanced utilities
107
+ console.log('\nšŸ”§ Step 2: Creating complete flow components...');
108
+ const flowComponents = (0, flow_structure_builder_1.createCompleteFlowComponents)(iPhoneFlowDefinition);
109
+ console.log('āœ… Flow components generated:');
110
+ console.log(` - Flow Record: ${flowComponents.flowRecord.sys_id}`);
111
+ console.log(` - Trigger Instance: ${flowComponents.triggerInstance.sys_id}`);
112
+ console.log(` - Action Instances: ${flowComponents.actionInstances.length}`);
113
+ console.log(` - Logic Chain: ${flowComponents.logicChain.length}`);
114
+ console.log(` - Variables: ${flowComponents.variables.length}`);
115
+ // Test 2: Generate enhanced XML
116
+ console.log('\nšŸ“„ Step 3: Generating enhanced XML...');
117
+ const flowXML = (0, flow_structure_builder_1.generateFlowXML)(flowComponents, {
118
+ includeMetadata: true,
119
+ validateBeforeExport: true,
120
+ compactFormat: false
121
+ });
122
+ console.log('āœ… XML generated successfully');
123
+ console.log(` - Size: ${flowXML.length} characters`);
124
+ console.log(` - Contains flow record: ${flowXML.includes('<sys_hub_flow>')}`);
125
+ console.log(` - Contains trigger: ${flowXML.includes('<sys_hub_trigger_instance>')}`);
126
+ console.log(` - Contains actions: ${flowXML.includes('<sys_hub_action_instance>')}`);
127
+ // Test 3: Deploy to ServiceNow using integrated client
128
+ console.log('\nšŸš€ Step 4: Deploying to ServiceNow...');
129
+ const flowData = {
130
+ name: iPhoneFlowDefinition.name,
131
+ description: iPhoneFlowDefinition.description,
132
+ trigger_type: iPhoneFlowDefinition.trigger.type,
133
+ table: iPhoneFlowDefinition.trigger.table,
134
+ condition: iPhoneFlowDefinition.trigger.condition,
135
+ activities: iPhoneFlowDefinition.activities,
136
+ variables: iPhoneFlowDefinition.variables
137
+ };
138
+ const deploymentResult = await client.createFlow(flowData);
139
+ if (deploymentResult.success) {
140
+ console.log('āœ… Flow deployed successfully!');
141
+ console.log(` - Flow ID: ${deploymentResult.data.sys_id}`);
142
+ console.log(` - Flow Name: ${deploymentResult.data.name}`);
143
+ console.log(` - Status: ${deploymentResult.data.status || 'published'}`);
144
+ console.log(` - Activities Created: ${deploymentResult.data.activities_created || 'N/A'}`);
145
+ console.log(` - Flow Designer URL: ${deploymentResult.data.flow_designer_url || 'N/A'}`);
146
+ // Test 4: Verify deployment
147
+ console.log('\nšŸ” Step 5: Verifying deployment...');
148
+ const flowContent = await client.checkFlowContent(deploymentResult.data.sys_id);
149
+ if (flowContent.hasContent) {
150
+ console.log('āœ… Flow verification successful!');
151
+ console.log(` - Has Content: ${flowContent.hasContent}`);
152
+ console.log(` - Activities Count: ${flowContent.details.activities_count}`);
153
+ console.log(` - Has Trigger: ${flowContent.details.has_trigger}`);
154
+ console.log(` - Active: ${flowContent.details.active}`);
155
+ }
156
+ else {
157
+ console.log('āš ļø Flow deployed but verification shows no content');
158
+ console.log(` - Details: ${flowContent.details}`);
159
+ }
160
+ }
161
+ else {
162
+ console.error('āŒ Flow deployment failed:', deploymentResult.error);
163
+ return false;
164
+ }
165
+ console.log('\nšŸŽ‰ Integration test completed successfully!');
166
+ console.log('All components are working together properly:');
167
+ console.log('āœ… Flow structure builder - generates complete components');
168
+ console.log('āœ… Enhanced XML generation - produces valid update sets');
169
+ console.log('āœ… ServiceNow client - creates flow with activities');
170
+ console.log('āœ… Activity creation integration - flow and action instances');
171
+ console.log('āœ… Verification system - confirms deployment success');
172
+ return true;
173
+ }
174
+ catch (error) {
175
+ console.error('āŒ Integration test failed:', error);
176
+ return false;
177
+ }
178
+ }
179
+ // Run the test if this file is executed directly
180
+ if (require.main === module) {
181
+ testIPhoneRequestApprovalFlow()
182
+ .then(success => {
183
+ process.exit(success ? 0 : 1);
184
+ })
185
+ .catch(error => {
186
+ console.error('Fatal error:', error);
187
+ process.exit(1);
188
+ });
189
+ }