snow-flow 1.1.42 → 1.1.43
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/mcp/servicenow-deployment-mcp.js +352 -0
- package/dist/mcp/servicenow-deployment-mcp.js.map +1 -1
- package/dist/mcp/servicenow-operations-mcp.js +332 -3
- package/dist/mcp/servicenow-operations-mcp.js.map +1 -1
- package/dist/mcp/servicenow-platform-development-mcp.js +187 -0
- package/dist/mcp/servicenow-platform-development-mcp.js.map +1 -1
- package/dist/utils/servicenow-client.d.ts +5 -0
- package/dist/utils/servicenow-client.d.ts.map +1 -1
- package/dist/utils/servicenow-client.js +73 -13
- package/dist/utils/servicenow-client.js.map +1 -1
- package/package.json +1 -1
|
@@ -368,6 +368,35 @@ class ServiceNowDeploymentMCP {
|
|
|
368
368
|
required: ['name'],
|
|
369
369
|
},
|
|
370
370
|
},
|
|
371
|
+
{
|
|
372
|
+
name: 'snow_bulk_deploy',
|
|
373
|
+
description: 'Deploy multiple artifacts in a single operation with transaction support',
|
|
374
|
+
inputSchema: {
|
|
375
|
+
type: 'object',
|
|
376
|
+
properties: {
|
|
377
|
+
artifacts: {
|
|
378
|
+
type: 'array',
|
|
379
|
+
description: 'Array of artifacts to deploy',
|
|
380
|
+
items: {
|
|
381
|
+
type: 'object',
|
|
382
|
+
properties: {
|
|
383
|
+
type: { type: 'string', enum: ['widget', 'flow', 'script', 'business_rule', 'table', 'application'] },
|
|
384
|
+
sys_id: { type: 'string', description: 'Existing artifact sys_id (for updates)' },
|
|
385
|
+
config: { type: 'object', description: 'Artifact configuration' },
|
|
386
|
+
action: { type: 'string', enum: ['create', 'update', 'deploy'], default: 'deploy' },
|
|
387
|
+
},
|
|
388
|
+
required: ['type', 'config'],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
transaction_mode: { type: 'boolean', description: 'All or nothing deployment', default: true },
|
|
392
|
+
parallel: { type: 'boolean', description: 'Deploy in parallel when possible', default: false },
|
|
393
|
+
dry_run: { type: 'boolean', description: 'Validate without deploying', default: false },
|
|
394
|
+
update_set_name: { type: 'string', description: 'Custom update set name' },
|
|
395
|
+
rollback_on_error: { type: 'boolean', description: 'Rollback all on any failure', default: true },
|
|
396
|
+
},
|
|
397
|
+
required: ['artifacts'],
|
|
398
|
+
},
|
|
399
|
+
},
|
|
371
400
|
],
|
|
372
401
|
}));
|
|
373
402
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
@@ -415,6 +444,8 @@ class ServiceNowDeploymentMCP {
|
|
|
415
444
|
return await this.createSolutionPackage(args);
|
|
416
445
|
case 'snow_flow_wizard':
|
|
417
446
|
return await this.flowWizard(args);
|
|
447
|
+
case 'snow_bulk_deploy':
|
|
448
|
+
return await this.bulkDeploy(args);
|
|
418
449
|
default:
|
|
419
450
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
420
451
|
}
|
|
@@ -2625,6 +2656,327 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
|
|
|
2625
2656
|
throw new Error(`Flow wizard failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2626
2657
|
}
|
|
2627
2658
|
}
|
|
2659
|
+
/**
|
|
2660
|
+
* Bulk Deploy Multiple Artifacts
|
|
2661
|
+
*/
|
|
2662
|
+
async bulkDeploy(args) {
|
|
2663
|
+
try {
|
|
2664
|
+
const { artifacts, transaction_mode = true, parallel = false, dry_run = false, update_set_name, rollback_on_error = true } = args;
|
|
2665
|
+
this.logger.info(`Starting bulk deployment of ${artifacts.length} artifacts`);
|
|
2666
|
+
// Create or ensure update set
|
|
2667
|
+
if (update_set_name) {
|
|
2668
|
+
await this.client.createUpdateSet({
|
|
2669
|
+
name: update_set_name,
|
|
2670
|
+
description: 'Bulk deployment from Snow-Flow',
|
|
2671
|
+
state: 'in_progress'
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
else {
|
|
2675
|
+
await this.client.ensureUpdateSet();
|
|
2676
|
+
}
|
|
2677
|
+
const results = {
|
|
2678
|
+
total: artifacts.length,
|
|
2679
|
+
successful: 0,
|
|
2680
|
+
failed: 0,
|
|
2681
|
+
skipped: 0,
|
|
2682
|
+
details: []
|
|
2683
|
+
};
|
|
2684
|
+
// Track deployed artifacts for rollback
|
|
2685
|
+
const deployedArtifacts = [];
|
|
2686
|
+
try {
|
|
2687
|
+
if (dry_run) {
|
|
2688
|
+
// Validation only
|
|
2689
|
+
for (const artifact of artifacts) {
|
|
2690
|
+
try {
|
|
2691
|
+
const validation = await this.validateArtifact(artifact);
|
|
2692
|
+
results.details.push({
|
|
2693
|
+
type: artifact.type,
|
|
2694
|
+
name: artifact.config?.name || 'Unknown',
|
|
2695
|
+
status: validation.valid ? '✅ Valid' : '❌ Invalid',
|
|
2696
|
+
message: validation.message
|
|
2697
|
+
});
|
|
2698
|
+
if (validation.valid) {
|
|
2699
|
+
results.successful++;
|
|
2700
|
+
}
|
|
2701
|
+
else {
|
|
2702
|
+
results.failed++;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
catch (error) {
|
|
2706
|
+
results.failed++;
|
|
2707
|
+
results.details.push({
|
|
2708
|
+
type: artifact.type,
|
|
2709
|
+
name: artifact.config?.name || 'Unknown',
|
|
2710
|
+
status: '❌ Error',
|
|
2711
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
else {
|
|
2717
|
+
// Actual deployment
|
|
2718
|
+
if (parallel && !transaction_mode) {
|
|
2719
|
+
// Parallel deployment (no transaction support)
|
|
2720
|
+
const deploymentPromises = artifacts.map(async (artifact) => {
|
|
2721
|
+
try {
|
|
2722
|
+
const result = await this.deployArtifact(artifact);
|
|
2723
|
+
if (result.success) {
|
|
2724
|
+
deployedArtifacts.push({ type: artifact.type, sys_id: result.sys_id });
|
|
2725
|
+
results.successful++;
|
|
2726
|
+
results.details.push({
|
|
2727
|
+
type: artifact.type,
|
|
2728
|
+
name: artifact.config?.name || 'Unknown',
|
|
2729
|
+
sys_id: result.sys_id,
|
|
2730
|
+
status: '✅ Deployed',
|
|
2731
|
+
message: result.message
|
|
2732
|
+
});
|
|
2733
|
+
}
|
|
2734
|
+
else {
|
|
2735
|
+
throw new Error(result.message);
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
catch (error) {
|
|
2739
|
+
results.failed++;
|
|
2740
|
+
results.details.push({
|
|
2741
|
+
type: artifact.type,
|
|
2742
|
+
name: artifact.config?.name || 'Unknown',
|
|
2743
|
+
status: '❌ Failed',
|
|
2744
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2745
|
+
});
|
|
2746
|
+
if (transaction_mode && rollback_on_error) {
|
|
2747
|
+
throw error; // Will trigger rollback
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
await Promise.all(deploymentPromises);
|
|
2752
|
+
}
|
|
2753
|
+
else {
|
|
2754
|
+
// Sequential deployment (supports transactions)
|
|
2755
|
+
for (const artifact of artifacts) {
|
|
2756
|
+
try {
|
|
2757
|
+
const result = await this.deployArtifact(artifact);
|
|
2758
|
+
if (result.success) {
|
|
2759
|
+
deployedArtifacts.push({ type: artifact.type, sys_id: result.sys_id });
|
|
2760
|
+
results.successful++;
|
|
2761
|
+
results.details.push({
|
|
2762
|
+
type: artifact.type,
|
|
2763
|
+
name: artifact.config?.name || 'Unknown',
|
|
2764
|
+
sys_id: result.sys_id,
|
|
2765
|
+
status: '✅ Deployed',
|
|
2766
|
+
message: result.message
|
|
2767
|
+
});
|
|
2768
|
+
}
|
|
2769
|
+
else {
|
|
2770
|
+
throw new Error(result.message);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
catch (error) {
|
|
2774
|
+
results.failed++;
|
|
2775
|
+
results.details.push({
|
|
2776
|
+
type: artifact.type,
|
|
2777
|
+
name: artifact.config?.name || 'Unknown',
|
|
2778
|
+
status: '❌ Failed',
|
|
2779
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2780
|
+
});
|
|
2781
|
+
if (transaction_mode && rollback_on_error) {
|
|
2782
|
+
throw error; // Will trigger rollback
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
catch (error) {
|
|
2790
|
+
// Rollback if needed
|
|
2791
|
+
if (rollback_on_error && deployedArtifacts.length > 0) {
|
|
2792
|
+
this.logger.info(`Rolling back ${deployedArtifacts.length} deployed artifacts`);
|
|
2793
|
+
for (const deployed of deployedArtifacts) {
|
|
2794
|
+
try {
|
|
2795
|
+
await this.rollbackArtifact(deployed);
|
|
2796
|
+
results.details.push({
|
|
2797
|
+
type: deployed.type,
|
|
2798
|
+
sys_id: deployed.sys_id,
|
|
2799
|
+
status: '🔄 Rolled back',
|
|
2800
|
+
message: 'Artifact rolled back due to deployment failure'
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
catch (rollbackError) {
|
|
2804
|
+
this.logger.error(`Failed to rollback ${deployed.type} ${deployed.sys_id}:`, rollbackError);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
throw error;
|
|
2809
|
+
}
|
|
2810
|
+
// Generate summary
|
|
2811
|
+
let summary = `🚀 Bulk Deployment ${dry_run ? 'Validation' : 'Complete'}\n\n`;
|
|
2812
|
+
summary += `📊 Summary:\n`;
|
|
2813
|
+
summary += ` Total: ${results.total}\n`;
|
|
2814
|
+
summary += ` ✅ Successful: ${results.successful}\n`;
|
|
2815
|
+
summary += ` ❌ Failed: ${results.failed}\n`;
|
|
2816
|
+
if (results.skipped > 0) {
|
|
2817
|
+
summary += ` ⏭️ Skipped: ${results.skipped}\n`;
|
|
2818
|
+
}
|
|
2819
|
+
summary += `\n📋 Details:\n`;
|
|
2820
|
+
for (const detail of results.details) {
|
|
2821
|
+
summary += `\n${detail.status} ${detail.type}: ${detail.name}`;
|
|
2822
|
+
if (detail.sys_id) {
|
|
2823
|
+
summary += ` (${detail.sys_id})`;
|
|
2824
|
+
}
|
|
2825
|
+
if (detail.message) {
|
|
2826
|
+
summary += `\n ${detail.message}`;
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
if (transaction_mode && !dry_run) {
|
|
2830
|
+
summary += `\n\n🔒 Transaction Mode: ${results.failed === 0 ? 'All deployed successfully' : 'Rolled back due to failures'}`;
|
|
2831
|
+
}
|
|
2832
|
+
return {
|
|
2833
|
+
content: [{
|
|
2834
|
+
type: 'text',
|
|
2835
|
+
text: summary
|
|
2836
|
+
}]
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
catch (error) {
|
|
2840
|
+
throw new Error(`Bulk deployment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
/**
|
|
2844
|
+
* Deploy a single artifact
|
|
2845
|
+
*/
|
|
2846
|
+
async deployArtifact(artifact) {
|
|
2847
|
+
const { type, sys_id, config, action = 'deploy' } = artifact;
|
|
2848
|
+
try {
|
|
2849
|
+
switch (type) {
|
|
2850
|
+
case 'widget':
|
|
2851
|
+
if (action === 'update' && sys_id) {
|
|
2852
|
+
const result = await this.client.updateRecord('sp_widget', sys_id, config);
|
|
2853
|
+
return {
|
|
2854
|
+
success: result.success,
|
|
2855
|
+
sys_id: sys_id,
|
|
2856
|
+
message: result.success ? 'Widget updated' : result.error
|
|
2857
|
+
};
|
|
2858
|
+
}
|
|
2859
|
+
else {
|
|
2860
|
+
const result = await this.deployWidget(config);
|
|
2861
|
+
return {
|
|
2862
|
+
success: result.content[0].text.includes('✅'),
|
|
2863
|
+
sys_id: result.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
|
|
2864
|
+
message: 'Widget deployed'
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
case 'flow':
|
|
2868
|
+
const flowResult = await this.deployFlow(config);
|
|
2869
|
+
return {
|
|
2870
|
+
success: flowResult.content[0].text.includes('✅'),
|
|
2871
|
+
sys_id: flowResult.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
|
|
2872
|
+
message: 'Flow deployed'
|
|
2873
|
+
};
|
|
2874
|
+
case 'script':
|
|
2875
|
+
case 'script_include':
|
|
2876
|
+
const scriptResult = await this.client.createRecord('sys_script_include', config);
|
|
2877
|
+
return {
|
|
2878
|
+
success: scriptResult.success,
|
|
2879
|
+
sys_id: scriptResult.data?.sys_id,
|
|
2880
|
+
message: scriptResult.success ? 'Script deployed' : scriptResult.error
|
|
2881
|
+
};
|
|
2882
|
+
case 'business_rule':
|
|
2883
|
+
const ruleResult = await this.client.createRecord('sys_script', config);
|
|
2884
|
+
return {
|
|
2885
|
+
success: ruleResult.success,
|
|
2886
|
+
sys_id: ruleResult.data?.sys_id,
|
|
2887
|
+
message: ruleResult.success ? 'Business rule deployed' : ruleResult.error
|
|
2888
|
+
};
|
|
2889
|
+
case 'table':
|
|
2890
|
+
const tableResult = await this.client.createRecord('sys_db_object', config);
|
|
2891
|
+
return {
|
|
2892
|
+
success: tableResult.success,
|
|
2893
|
+
sys_id: tableResult.data?.sys_id,
|
|
2894
|
+
message: tableResult.success ? 'Table created' : tableResult.error
|
|
2895
|
+
};
|
|
2896
|
+
case 'application':
|
|
2897
|
+
const appResult = await this.deployApplication(config);
|
|
2898
|
+
return {
|
|
2899
|
+
success: appResult.content[0].text.includes('✅'),
|
|
2900
|
+
sys_id: appResult.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
|
|
2901
|
+
message: 'Application deployed'
|
|
2902
|
+
};
|
|
2903
|
+
default:
|
|
2904
|
+
return {
|
|
2905
|
+
success: false,
|
|
2906
|
+
message: `Unknown artifact type: ${type}`
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
catch (error) {
|
|
2911
|
+
return {
|
|
2912
|
+
success: false,
|
|
2913
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Validate artifact before deployment
|
|
2919
|
+
*/
|
|
2920
|
+
async validateArtifact(artifact) {
|
|
2921
|
+
const { type, config } = artifact;
|
|
2922
|
+
// Basic validation
|
|
2923
|
+
if (!type || !config) {
|
|
2924
|
+
return { valid: false, message: 'Missing type or config' };
|
|
2925
|
+
}
|
|
2926
|
+
// Type-specific validation
|
|
2927
|
+
switch (type) {
|
|
2928
|
+
case 'widget':
|
|
2929
|
+
if (!config.name || !config.template) {
|
|
2930
|
+
return { valid: false, message: 'Widget requires name and template' };
|
|
2931
|
+
}
|
|
2932
|
+
break;
|
|
2933
|
+
case 'flow':
|
|
2934
|
+
if (!config.name || !config.definition) {
|
|
2935
|
+
return { valid: false, message: 'Flow requires name and definition' };
|
|
2936
|
+
}
|
|
2937
|
+
break;
|
|
2938
|
+
case 'script':
|
|
2939
|
+
case 'script_include':
|
|
2940
|
+
if (!config.name || !config.script) {
|
|
2941
|
+
return { valid: false, message: 'Script requires name and script content' };
|
|
2942
|
+
}
|
|
2943
|
+
break;
|
|
2944
|
+
case 'business_rule':
|
|
2945
|
+
if (!config.name || !config.collection || !config.script) {
|
|
2946
|
+
return { valid: false, message: 'Business rule requires name, collection, and script' };
|
|
2947
|
+
}
|
|
2948
|
+
break;
|
|
2949
|
+
case 'table':
|
|
2950
|
+
if (!config.name || !config.label) {
|
|
2951
|
+
return { valid: false, message: 'Table requires name and label' };
|
|
2952
|
+
}
|
|
2953
|
+
break;
|
|
2954
|
+
case 'application':
|
|
2955
|
+
if (!config.name || !config.scope) {
|
|
2956
|
+
return { valid: false, message: 'Application requires name and scope' };
|
|
2957
|
+
}
|
|
2958
|
+
break;
|
|
2959
|
+
}
|
|
2960
|
+
return { valid: true, message: 'Validation passed' };
|
|
2961
|
+
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Rollback deployed artifact
|
|
2964
|
+
*/
|
|
2965
|
+
async rollbackArtifact(artifact) {
|
|
2966
|
+
const tableMap = {
|
|
2967
|
+
'widget': 'sp_widget',
|
|
2968
|
+
'flow': 'sys_hub_flow',
|
|
2969
|
+
'script': 'sys_script_include',
|
|
2970
|
+
'script_include': 'sys_script_include',
|
|
2971
|
+
'business_rule': 'sys_script',
|
|
2972
|
+
'table': 'sys_db_object',
|
|
2973
|
+
'application': 'sys_app'
|
|
2974
|
+
};
|
|
2975
|
+
const table = tableMap[artifact.type];
|
|
2976
|
+
if (table) {
|
|
2977
|
+
await this.client.deleteRecord(table, artifact.sys_id);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2628
2980
|
/**
|
|
2629
2981
|
* Extract dependencies from flow definition
|
|
2630
2982
|
*/
|