snow-flow 1.1.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.
- package/.env.example +49 -0
- package/.mcp.json +106 -0
- package/.mcp.json.template +106 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/bin/snow-flow +4 -0
- package/bin/snow-flow.js +3 -0
- package/claude-flow +79 -0
- package/claude-flow.bat +18 -0
- package/claude-flow.config.json +20 -0
- package/claude-flow.ps1 +24 -0
- package/dist/agents/app-creator.agent.d.ts +55 -0
- package/dist/agents/app-creator.agent.d.ts.map +1 -0
- package/dist/agents/app-creator.agent.js +1292 -0
- package/dist/agents/app-creator.agent.js.map +1 -0
- package/dist/agents/base-snow-agent.d.ts +63 -0
- package/dist/agents/base-snow-agent.d.ts.map +1 -0
- package/dist/agents/base-snow-agent.js +296 -0
- package/dist/agents/base-snow-agent.js.map +1 -0
- package/dist/agents/script-generator.agent.d.ts +32 -0
- package/dist/agents/script-generator.agent.d.ts.map +1 -0
- package/dist/agents/script-generator.agent.js +772 -0
- package/dist/agents/script-generator.agent.js.map +1 -0
- package/dist/agents/ui-builder.agent.d.ts +50 -0
- package/dist/agents/ui-builder.agent.d.ts.map +1 -0
- package/dist/agents/ui-builder.agent.js +1539 -0
- package/dist/agents/ui-builder.agent.js.map +1 -0
- package/dist/agents/widget-builder.agent.d.ts +32 -0
- package/dist/agents/widget-builder.agent.d.ts.map +1 -0
- package/dist/agents/widget-builder.agent.js +439 -0
- package/dist/agents/widget-builder.agent.js.map +1 -0
- package/dist/agents/workflow-designer.agent.d.ts +31 -0
- package/dist/agents/workflow-designer.agent.d.ts.map +1 -0
- package/dist/agents/workflow-designer.agent.js +583 -0
- package/dist/agents/workflow-designer.agent.js.map +1 -0
- package/dist/api/error-handling.d.ts +214 -0
- package/dist/api/error-handling.d.ts.map +1 -0
- package/dist/api/error-handling.js +594 -0
- package/dist/api/error-handling.js.map +1 -0
- package/dist/api/flow-designer-api.d.ts +167 -0
- package/dist/api/flow-designer-api.d.ts.map +1 -0
- package/dist/api/flow-designer-api.js +555 -0
- package/dist/api/flow-designer-api.js.map +1 -0
- package/dist/api/natural-language-mapper.d.ts +126 -0
- package/dist/api/natural-language-mapper.d.ts.map +1 -0
- package/dist/api/natural-language-mapper.js +498 -0
- package/dist/api/natural-language-mapper.js.map +1 -0
- package/dist/api/performance-optimizer.d.ts +240 -0
- package/dist/api/performance-optimizer.d.ts.map +1 -0
- package/dist/api/performance-optimizer.js +701 -0
- package/dist/api/performance-optimizer.js.map +1 -0
- package/dist/api/transaction-manager.d.ts +189 -0
- package/dist/api/transaction-manager.d.ts.map +1 -0
- package/dist/api/transaction-manager.js +576 -0
- package/dist/api/transaction-manager.js.map +1 -0
- package/dist/cli/deploy-artifact.d.ts +7 -0
- package/dist/cli/deploy-artifact.d.ts.map +1 -0
- package/dist/cli/deploy-artifact.js +279 -0
- package/dist/cli/deploy-artifact.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2057 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/managers/scope-manager.d.ts +75 -0
- package/dist/managers/scope-manager.d.ts.map +1 -0
- package/dist/managers/scope-manager.js +448 -0
- package/dist/managers/scope-manager.js.map +1 -0
- package/dist/mcp/mcp-wrapper.d.ts +8 -0
- package/dist/mcp/mcp-wrapper.d.ts.map +1 -0
- package/dist/mcp/mcp-wrapper.js +77 -0
- package/dist/mcp/mcp-wrapper.js.map +1 -0
- package/dist/mcp/servicenow-automation-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-automation-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-automation-mcp.js +683 -0
- package/dist/mcp/servicenow-automation-mcp.js.map +1 -0
- package/dist/mcp/servicenow-deployment-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-deployment-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-deployment-mcp.js +972 -0
- package/dist/mcp/servicenow-deployment-mcp.js.map +1 -0
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-flow-composer-mcp.js +1121 -0
- package/dist/mcp/servicenow-flow-composer-mcp.js.map +1 -0
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-graph-memory-mcp.js +703 -0
- package/dist/mcp/servicenow-graph-memory-mcp.js.map +1 -0
- package/dist/mcp/servicenow-integration-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-integration-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-integration-mcp.js +689 -0
- package/dist/mcp/servicenow-integration-mcp.js.map +1 -0
- package/dist/mcp/servicenow-intelligent-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-intelligent-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-intelligent-mcp.js +1138 -0
- package/dist/mcp/servicenow-intelligent-mcp.js.map +1 -0
- package/dist/mcp/servicenow-mcp-server.d.ts +37 -0
- package/dist/mcp/servicenow-mcp-server.d.ts.map +1 -0
- package/dist/mcp/servicenow-mcp-server.js +648 -0
- package/dist/mcp/servicenow-mcp-server.js.map +1 -0
- package/dist/mcp/servicenow-operations-mcp.d.ts +15 -0
- package/dist/mcp/servicenow-operations-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-operations-mcp.js +1287 -0
- package/dist/mcp/servicenow-operations-mcp.js.map +1 -0
- package/dist/mcp/servicenow-platform-development-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-platform-development-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-platform-development-mcp.js +557 -0
- package/dist/mcp/servicenow-platform-development-mcp.js.map +1 -0
- package/dist/mcp/servicenow-progressive-indexer.d.ts +79 -0
- package/dist/mcp/servicenow-progressive-indexer.d.ts.map +1 -0
- package/dist/mcp/servicenow-progressive-indexer.js +320 -0
- package/dist/mcp/servicenow-progressive-indexer.js.map +1 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +888 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js.map +1 -0
- package/dist/mcp/servicenow-security-compliance-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-security-compliance-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-security-compliance-mcp.js +812 -0
- package/dist/mcp/servicenow-security-compliance-mcp.js.map +1 -0
- package/dist/mcp/servicenow-update-set-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-update-set-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-update-set-mcp.js +599 -0
- package/dist/mcp/servicenow-update-set-mcp.js.map +1 -0
- package/dist/mcp/start-all-mcp-servers.d.ts +6 -0
- package/dist/mcp/start-all-mcp-servers.d.ts.map +1 -0
- package/dist/mcp/start-all-mcp-servers.js +65 -0
- package/dist/mcp/start-all-mcp-servers.js.map +1 -0
- package/dist/mcp/start-servicenow-mcp.d.ts +7 -0
- package/dist/mcp/start-servicenow-mcp.d.ts.map +1 -0
- package/dist/mcp/start-servicenow-mcp.js +64 -0
- package/dist/mcp/start-servicenow-mcp.js.map +1 -0
- package/dist/mcp/test-simple-mcp.d.ts +6 -0
- package/dist/mcp/test-simple-mcp.d.ts.map +1 -0
- package/dist/mcp/test-simple-mcp.js +64 -0
- package/dist/mcp/test-simple-mcp.js.map +1 -0
- package/dist/orchestrator/flow-composer.d.ts +269 -0
- package/dist/orchestrator/flow-composer.d.ts.map +1 -0
- package/dist/orchestrator/flow-composer.js +2221 -0
- package/dist/orchestrator/flow-composer.js.map +1 -0
- package/dist/orchestrator/flow-pattern-templates.d.ts +260 -0
- package/dist/orchestrator/flow-pattern-templates.d.ts.map +1 -0
- package/dist/orchestrator/flow-pattern-templates.js +906 -0
- package/dist/orchestrator/flow-pattern-templates.js.map +1 -0
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts +202 -0
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts.map +1 -0
- package/dist/orchestrator/flow-subflow-decision-engine.js +769 -0
- package/dist/orchestrator/flow-subflow-decision-engine.js.map +1 -0
- package/dist/orchestrator/flow-validation-engine.d.ts +145 -0
- package/dist/orchestrator/flow-validation-engine.d.ts.map +1 -0
- package/dist/orchestrator/flow-validation-engine.js +663 -0
- package/dist/orchestrator/flow-validation-engine.js.map +1 -0
- package/dist/orchestrator/snow-orchestrator.d.ts +49 -0
- package/dist/orchestrator/snow-orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/snow-orchestrator.js +235 -0
- package/dist/orchestrator/snow-orchestrator.js.map +1 -0
- package/dist/orchestrator/subflow-creation-handler.d.ts +230 -0
- package/dist/orchestrator/subflow-creation-handler.d.ts.map +1 -0
- package/dist/orchestrator/subflow-creation-handler.js +791 -0
- package/dist/orchestrator/subflow-creation-handler.js.map +1 -0
- package/dist/strategies/global-scope-strategy.d.ts +123 -0
- package/dist/strategies/global-scope-strategy.d.ts.map +1 -0
- package/dist/strategies/global-scope-strategy.js +585 -0
- package/dist/strategies/global-scope-strategy.js.map +1 -0
- package/dist/types/index.d.ts +138 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/servicenow.types.d.ts +260 -0
- package/dist/types/servicenow.types.d.ts.map +1 -0
- package/dist/types/servicenow.types.js +3 -0
- package/dist/types/servicenow.types.js.map +1 -0
- package/dist/types/snow-flow.types.d.ts +114 -0
- package/dist/types/snow-flow.types.d.ts.map +1 -0
- package/dist/types/snow-flow.types.js +3 -0
- package/dist/types/snow-flow.types.js.map +1 -0
- package/dist/utils/action-type-cache.d.ts +66 -0
- package/dist/utils/action-type-cache.d.ts.map +1 -0
- package/dist/utils/action-type-cache.js +237 -0
- package/dist/utils/action-type-cache.js.map +1 -0
- package/dist/utils/agent-detector.d.ts +35 -0
- package/dist/utils/agent-detector.d.ts.map +1 -0
- package/dist/utils/agent-detector.js +353 -0
- package/dist/utils/agent-detector.js.map +1 -0
- package/dist/utils/flow-api-discovery.d.ts +151 -0
- package/dist/utils/flow-api-discovery.d.ts.map +1 -0
- package/dist/utils/flow-api-discovery.js +440 -0
- package/dist/utils/flow-api-discovery.js.map +1 -0
- package/dist/utils/flow-xml-generator.d.ts +41 -0
- package/dist/utils/flow-xml-generator.d.ts.map +1 -0
- package/dist/utils/flow-xml-generator.js +258 -0
- package/dist/utils/flow-xml-generator.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mcp-auth-middleware.d.ts +58 -0
- package/dist/utils/mcp-auth-middleware.d.ts.map +1 -0
- package/dist/utils/mcp-auth-middleware.js +227 -0
- package/dist/utils/mcp-auth-middleware.js.map +1 -0
- package/dist/utils/mcp-config-manager.d.ts +126 -0
- package/dist/utils/mcp-config-manager.d.ts.map +1 -0
- package/dist/utils/mcp-config-manager.js +209 -0
- package/dist/utils/mcp-config-manager.js.map +1 -0
- package/dist/utils/mcp-server-manager.d.ts +91 -0
- package/dist/utils/mcp-server-manager.d.ts.map +1 -0
- package/dist/utils/mcp-server-manager.js +338 -0
- package/dist/utils/mcp-server-manager.js.map +1 -0
- package/dist/utils/scope-utils.d.ts +72 -0
- package/dist/utils/scope-utils.d.ts.map +1 -0
- package/dist/utils/scope-utils.js +386 -0
- package/dist/utils/scope-utils.js.map +1 -0
- package/dist/utils/servicenow-client.d.ts +233 -0
- package/dist/utils/servicenow-client.d.ts.map +1 -0
- package/dist/utils/servicenow-client.js +1465 -0
- package/dist/utils/servicenow-client.js.map +1 -0
- package/dist/utils/snow-oauth-old.d.ts +65 -0
- package/dist/utils/snow-oauth-old.d.ts.map +1 -0
- package/dist/utils/snow-oauth-old.js +345 -0
- package/dist/utils/snow-oauth-old.js.map +1 -0
- package/dist/utils/snow-oauth.d.ts +85 -0
- package/dist/utils/snow-oauth.d.ts.map +1 -0
- package/dist/utils/snow-oauth.js +512 -0
- package/dist/utils/snow-oauth.js.map +1 -0
- package/dist/utils/template-engine.d.ts +76 -0
- package/dist/utils/template-engine.d.ts.map +1 -0
- package/dist/utils/template-engine.js +391 -0
- package/dist/utils/template-engine.js.map +1 -0
- package/dist/version.d.ts +35 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +72 -0
- package/dist/version.js.map +1 -0
- package/mcp-wrapper.sh +12 -0
- package/package.json +77 -0
- package/reports/swarm-auto-centralized-1752649029776.json +13 -0
- package/scripts/postinstall.js +30 -0
- package/scripts/setup-mcp.js +89 -0
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ServiceNow Deployment MCP Server
|
|
5
|
+
* Provides specialized deployment tools for ServiceNow artifacts
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
9
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
10
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
11
|
+
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
12
|
+
const snow_oauth_js_1 = require("../utils/snow-oauth.js");
|
|
13
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
14
|
+
const scope_manager_js_1 = require("../managers/scope-manager.js");
|
|
15
|
+
const global_scope_strategy_js_1 = require("../strategies/global-scope-strategy.js");
|
|
16
|
+
const fs_1 = require("fs");
|
|
17
|
+
const path_1 = require("path");
|
|
18
|
+
class ServiceNowDeploymentMCP {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.server = new index_js_1.Server({
|
|
21
|
+
name: 'servicenow-deployment',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
}, {
|
|
24
|
+
capabilities: {
|
|
25
|
+
tools: {},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
29
|
+
this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
30
|
+
this.logger = new logger_js_1.Logger('ServiceNowDeploymentMCP');
|
|
31
|
+
// Initialize global scope management
|
|
32
|
+
this.scopeManager = new scope_manager_js_1.ScopeManager({
|
|
33
|
+
defaultScope: global_scope_strategy_js_1.ScopeType.GLOBAL,
|
|
34
|
+
allowFallback: true,
|
|
35
|
+
validatePermissions: true,
|
|
36
|
+
enableMigration: false
|
|
37
|
+
});
|
|
38
|
+
this.globalScopeStrategy = new global_scope_strategy_js_1.GlobalScopeStrategy();
|
|
39
|
+
this.setupHandlers();
|
|
40
|
+
}
|
|
41
|
+
setupHandlers() {
|
|
42
|
+
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
43
|
+
tools: [
|
|
44
|
+
{
|
|
45
|
+
name: 'snow_deploy_widget',
|
|
46
|
+
description: 'AUTONOMOUS widget deployment - deploys directly to ServiceNow, returns live URLs, handles errors automatically. NO MANUAL STEPS!',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
name: { type: 'string', description: 'Widget internal name (e.g., incident_dashboard)' },
|
|
51
|
+
title: { type: 'string', description: 'Widget display title' },
|
|
52
|
+
description: { type: 'string', description: 'Widget description' },
|
|
53
|
+
template: { type: 'string', description: 'HTML template content' },
|
|
54
|
+
css: { type: 'string', description: 'CSS styles' },
|
|
55
|
+
client_script: { type: 'string', description: 'Client-side JavaScript' },
|
|
56
|
+
server_script: { type: 'string', description: 'Server-side script' },
|
|
57
|
+
option_schema: { type: 'string', description: 'Widget options JSON schema' },
|
|
58
|
+
demo_data: { type: 'string', description: 'Demo data JSON' },
|
|
59
|
+
category: { type: 'string', description: 'Widget category' },
|
|
60
|
+
},
|
|
61
|
+
required: ['name', 'title', 'template'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'snow_deploy_flow',
|
|
66
|
+
description: 'AUTONOMOUS flow deployment - creates complete flows with linked artifacts, auto-deploys dependencies, self-healing. FULLY AUTOMATED!',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
name: { type: 'string', description: 'Flow name' },
|
|
71
|
+
description: { type: 'string', description: 'Flow description' },
|
|
72
|
+
table: { type: 'string', description: 'Target table (e.g., sc_request, incident)' },
|
|
73
|
+
trigger_type: { type: 'string', enum: ['record_created', 'record_updated', 'scheduled', 'manual'], description: 'Flow trigger type' },
|
|
74
|
+
condition: { type: 'string', description: 'Trigger condition (encoded query)' },
|
|
75
|
+
active: { type: 'boolean', description: 'Activate flow on deployment' },
|
|
76
|
+
flow_definition: { type: 'string', description: 'Flow Designer definition JSON' },
|
|
77
|
+
category: { type: 'string', description: 'Flow category (e.g., approval, automation)' },
|
|
78
|
+
},
|
|
79
|
+
required: ['name', 'description', 'flow_definition', 'trigger_type'],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'snow_deploy_application',
|
|
84
|
+
description: 'INTELLIGENT scope-aware application deployment - automatically selects optimal scope (global/application), validates permissions, handles fallbacks',
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
name: { type: 'string', description: 'Application name' },
|
|
89
|
+
scope: { type: 'string', description: 'Preferred scope (global/application-specific) - leave blank for intelligent selection' },
|
|
90
|
+
version: { type: 'string', description: 'Application version' },
|
|
91
|
+
short_description: { type: 'string', description: 'Short description' },
|
|
92
|
+
description: { type: 'string', description: 'Full description' },
|
|
93
|
+
vendor: { type: 'string', description: 'Vendor name' },
|
|
94
|
+
vendor_prefix: { type: 'string', description: 'Vendor prefix' },
|
|
95
|
+
active: { type: 'boolean', description: 'Activate application' },
|
|
96
|
+
scope_strategy: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
enum: ['global', 'application', 'auto'],
|
|
99
|
+
description: 'Scope deployment strategy - auto selects optimal scope',
|
|
100
|
+
default: 'auto'
|
|
101
|
+
},
|
|
102
|
+
environment: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
enum: ['development', 'testing', 'production'],
|
|
105
|
+
description: 'Deployment environment',
|
|
106
|
+
default: 'development'
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
required: ['name', 'version'],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'snow_deploy_update_set',
|
|
114
|
+
description: 'Create and populate an update set for deployment',
|
|
115
|
+
inputSchema: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
properties: {
|
|
118
|
+
name: { type: 'string', description: 'Update set name' },
|
|
119
|
+
description: { type: 'string', description: 'Update set description' },
|
|
120
|
+
artifacts: {
|
|
121
|
+
type: 'array',
|
|
122
|
+
description: 'List of artifacts to include',
|
|
123
|
+
items: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
type: { type: 'string', enum: ['widget', 'workflow', 'script', 'table'] },
|
|
127
|
+
sys_id: { type: 'string', description: 'Sys ID of the artifact' },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
required: ['name', 'artifacts'],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: 'snow_validate_deployment',
|
|
137
|
+
description: 'Validate a deployment before executing',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
type: { type: 'string', enum: ['widget', 'workflow', 'application'] },
|
|
142
|
+
artifact: { type: 'object', description: 'The artifact to validate' },
|
|
143
|
+
},
|
|
144
|
+
required: ['type', 'artifact'],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'snow_rollback_deployment',
|
|
149
|
+
description: 'Rollback a recent deployment',
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
update_set_id: { type: 'string', description: 'Update set sys_id to rollback' },
|
|
154
|
+
reason: { type: 'string', description: 'Reason for rollback' },
|
|
155
|
+
},
|
|
156
|
+
required: ['update_set_id', 'reason'],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'snow_deployment_status',
|
|
161
|
+
description: 'Check deployment status and history',
|
|
162
|
+
inputSchema: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
properties: {
|
|
165
|
+
limit: { type: 'number', description: 'Number of recent deployments to show', default: 10 },
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'snow_export_artifact',
|
|
171
|
+
description: 'Export an artifact from ServiceNow for backup or migration',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
type: { type: 'string', enum: ['widget', 'workflow', 'application'] },
|
|
176
|
+
sys_id: { type: 'string', description: 'Sys ID of the artifact' },
|
|
177
|
+
format: { type: 'string', enum: ['json', 'xml', 'update_set'], default: 'json' },
|
|
178
|
+
},
|
|
179
|
+
required: ['type', 'sys_id'],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'snow_import_artifact',
|
|
184
|
+
description: 'Import an artifact from file to ServiceNow',
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
type: { type: 'string', enum: ['widget', 'workflow', 'application'] },
|
|
189
|
+
file_path: { type: 'string', description: 'Path to the artifact file' },
|
|
190
|
+
format: { type: 'string', enum: ['json', 'xml', 'update_set'], default: 'json' },
|
|
191
|
+
},
|
|
192
|
+
required: ['type', 'file_path'],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'snow_clone_instance_artifact',
|
|
197
|
+
description: 'Clone an artifact between ServiceNow instances',
|
|
198
|
+
inputSchema: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
source_instance: { type: 'string', description: 'Source instance URL' },
|
|
202
|
+
target_instance: { type: 'string', description: 'Target instance URL' },
|
|
203
|
+
type: { type: 'string', enum: ['widget', 'workflow', 'application'] },
|
|
204
|
+
sys_id: { type: 'string', description: 'Sys ID of the artifact to clone' },
|
|
205
|
+
},
|
|
206
|
+
required: ['source_instance', 'target_instance', 'type', 'sys_id'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
}));
|
|
211
|
+
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
212
|
+
const { name, arguments: args } = request.params;
|
|
213
|
+
try {
|
|
214
|
+
// Note: Authentication check moved to individual tool methods
|
|
215
|
+
// This allows the MCP server to start without credentials
|
|
216
|
+
// and fail gracefully when tools are actually used
|
|
217
|
+
switch (name) {
|
|
218
|
+
case 'snow_deploy_widget':
|
|
219
|
+
return await this.deployWidget(args);
|
|
220
|
+
case 'snow_deploy_flow':
|
|
221
|
+
return await this.deployFlow(args);
|
|
222
|
+
case 'snow_deploy_application':
|
|
223
|
+
return await this.deployApplication(args);
|
|
224
|
+
case 'snow_deploy_update_set':
|
|
225
|
+
return await this.deployUpdateSet(args);
|
|
226
|
+
case 'snow_validate_deployment':
|
|
227
|
+
return await this.validateDeployment(args);
|
|
228
|
+
case 'snow_rollback_deployment':
|
|
229
|
+
return await this.rollbackDeployment(args);
|
|
230
|
+
case 'snow_deployment_status':
|
|
231
|
+
return await this.getDeploymentStatus(args);
|
|
232
|
+
case 'snow_export_artifact':
|
|
233
|
+
return await this.exportArtifact(args);
|
|
234
|
+
case 'snow_import_artifact':
|
|
235
|
+
return await this.importArtifact(args);
|
|
236
|
+
case 'snow_clone_instance_artifact':
|
|
237
|
+
return await this.cloneInstanceArtifact(args);
|
|
238
|
+
default:
|
|
239
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
this.logger.error(`Tool execution failed: ${name}`, error);
|
|
244
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, error instanceof Error ? error.message : String(error));
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Ensure an Update Set is active before deployment
|
|
250
|
+
*/
|
|
251
|
+
async ensureUpdateSet(artifactType, artifactName) {
|
|
252
|
+
// Check if there's a current Update Set
|
|
253
|
+
const currentUpdateSet = await this.client.getCurrentUpdateSet();
|
|
254
|
+
if (currentUpdateSet.success && currentUpdateSet.data) {
|
|
255
|
+
this.logger.info('Using existing Update Set', {
|
|
256
|
+
name: currentUpdateSet.data.name,
|
|
257
|
+
id: currentUpdateSet.data.sys_id
|
|
258
|
+
});
|
|
259
|
+
return {
|
|
260
|
+
updateSetId: currentUpdateSet.data.sys_id,
|
|
261
|
+
updateSetName: currentUpdateSet.data.name
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// No current Update Set - create one automatically
|
|
265
|
+
const updateSetName = `Auto: ${artifactType} - ${artifactName} - ${new Date().toISOString().split('T')[0]}`;
|
|
266
|
+
const createResult = await this.client.createUpdateSet({
|
|
267
|
+
name: updateSetName,
|
|
268
|
+
description: `Automatically created for ${artifactType} deployment: ${artifactName}`,
|
|
269
|
+
state: 'in_progress'
|
|
270
|
+
});
|
|
271
|
+
if (!createResult.success) {
|
|
272
|
+
throw new Error(`Failed to create Update Set: ${createResult.error}`);
|
|
273
|
+
}
|
|
274
|
+
// Set as current
|
|
275
|
+
await this.client.setCurrentUpdateSet(createResult.data.sys_id);
|
|
276
|
+
this.logger.info('Created new Update Set', {
|
|
277
|
+
name: updateSetName,
|
|
278
|
+
id: createResult.data.sys_id
|
|
279
|
+
});
|
|
280
|
+
return {
|
|
281
|
+
updateSetId: createResult.data.sys_id,
|
|
282
|
+
updateSetName: updateSetName
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
async deployWidget(args) {
|
|
286
|
+
try {
|
|
287
|
+
// Check authentication first
|
|
288
|
+
const isAuth = await this.oauth.isAuthenticated();
|
|
289
|
+
if (!isAuth) {
|
|
290
|
+
return {
|
|
291
|
+
content: [
|
|
292
|
+
{
|
|
293
|
+
type: 'text',
|
|
294
|
+
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
this.logger.info('Deploying widget to ServiceNow', { name: args.name });
|
|
300
|
+
// Try to ensure Update Set is active (optional for now)
|
|
301
|
+
let updateSetId, updateSetName;
|
|
302
|
+
try {
|
|
303
|
+
const updateSetResult = await this.ensureUpdateSet('Widget', args.name);
|
|
304
|
+
updateSetId = updateSetResult.updateSetId;
|
|
305
|
+
updateSetName = updateSetResult.updateSetName;
|
|
306
|
+
this.logger.info('Using Update Set', { updateSetName, updateSetId });
|
|
307
|
+
}
|
|
308
|
+
catch (updateSetError) {
|
|
309
|
+
this.logger.warn('Could not create/use Update Set, proceeding without it', updateSetError);
|
|
310
|
+
updateSetId = null;
|
|
311
|
+
updateSetName = 'Direct deployment (no update set)';
|
|
312
|
+
}
|
|
313
|
+
// Validate widget structure
|
|
314
|
+
if (!args.template || !args.name || !args.title) {
|
|
315
|
+
throw new Error('Widget must have name, title, and template');
|
|
316
|
+
}
|
|
317
|
+
// Create widget in ServiceNow
|
|
318
|
+
const result = await this.client.createWidget({
|
|
319
|
+
name: args.name,
|
|
320
|
+
id: args.name,
|
|
321
|
+
title: args.title,
|
|
322
|
+
description: args.description || '',
|
|
323
|
+
template: args.template,
|
|
324
|
+
css: args.css || '',
|
|
325
|
+
client_script: args.client_script || '',
|
|
326
|
+
server_script: args.server_script || '',
|
|
327
|
+
option_schema: args.option_schema || '[]',
|
|
328
|
+
demo_data: args.demo_data || '{}',
|
|
329
|
+
has_preview: true,
|
|
330
|
+
category: args.category || 'custom',
|
|
331
|
+
});
|
|
332
|
+
if (result.success && result.data) {
|
|
333
|
+
// Get instance URL for direct link
|
|
334
|
+
const credentials = await this.oauth.loadCredentials();
|
|
335
|
+
const widgetUrl = `https://${credentials?.instance}/sp_config?id=widget_editor&sys_id=${result.data.sys_id}`;
|
|
336
|
+
return {
|
|
337
|
+
content: [
|
|
338
|
+
{
|
|
339
|
+
type: 'text',
|
|
340
|
+
text: `✅ Widget deployed successfully!
|
|
341
|
+
|
|
342
|
+
🎯 Widget Details:
|
|
343
|
+
- Name: ${args.name}
|
|
344
|
+
- Title: ${args.title}
|
|
345
|
+
- Sys ID: ${result.data.sys_id}
|
|
346
|
+
|
|
347
|
+
📦 Update Set:
|
|
348
|
+
- Name: ${updateSetName}
|
|
349
|
+
- ID: ${updateSetId}
|
|
350
|
+
- Category: ${args.category || 'custom'}
|
|
351
|
+
|
|
352
|
+
🔗 Direct Links:
|
|
353
|
+
- Widget Editor: ${widgetUrl}
|
|
354
|
+
- Service Portal Designer: https://${credentials?.instance}/sp_config?id=designer
|
|
355
|
+
|
|
356
|
+
📝 Next Steps:
|
|
357
|
+
1. Add the widget to a Service Portal page
|
|
358
|
+
2. Configure widget instance options
|
|
359
|
+
3. Test in different portal themes
|
|
360
|
+
4. Create update set for production deployment`,
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
throw new Error(result.error || 'Failed to deploy widget');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
throw new Error(`Widget deployment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async deployFlow(args) {
|
|
374
|
+
try {
|
|
375
|
+
// Check authentication first
|
|
376
|
+
const isAuth = await this.oauth.isAuthenticated();
|
|
377
|
+
if (!isAuth) {
|
|
378
|
+
return {
|
|
379
|
+
content: [
|
|
380
|
+
{
|
|
381
|
+
type: 'text',
|
|
382
|
+
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
this.logger.info('Deploying Flow Designer flow to ServiceNow', { name: args.name });
|
|
388
|
+
// Ensure Update Set is active
|
|
389
|
+
const { updateSetId, updateSetName } = await this.ensureUpdateSet('Flow', args.name);
|
|
390
|
+
// Check if this is a master flow with linked artifacts
|
|
391
|
+
const isComposedFlow = args.composed_flow || args.linked_artifacts;
|
|
392
|
+
const linkedArtifacts = args.linked_artifacts || [];
|
|
393
|
+
// Deploy linked artifacts first if this is a composed flow
|
|
394
|
+
const deployedArtifacts = [];
|
|
395
|
+
if (isComposedFlow && linkedArtifacts.length > 0) {
|
|
396
|
+
this.logger.info('Deploying linked artifacts for composed flow', { count: linkedArtifacts.length });
|
|
397
|
+
for (const artifact of linkedArtifacts) {
|
|
398
|
+
try {
|
|
399
|
+
const deployResult = await this.deployLinkedArtifact(artifact);
|
|
400
|
+
deployedArtifacts.push(deployResult);
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
this.logger.error('Failed to deploy linked artifact', { artifact, error });
|
|
404
|
+
throw new Error(`Failed to deploy linked artifact ${artifact.name}: ${error}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// Parse flow definition to inject deployed artifact references
|
|
409
|
+
let flowDefinition = args.flow_definition;
|
|
410
|
+
if (typeof flowDefinition === 'string') {
|
|
411
|
+
flowDefinition = JSON.parse(flowDefinition);
|
|
412
|
+
}
|
|
413
|
+
// Update flow activities with deployed artifact sys_ids
|
|
414
|
+
if (flowDefinition.activities && deployedArtifacts.length > 0) {
|
|
415
|
+
flowDefinition.activities = flowDefinition.activities.map((activity) => {
|
|
416
|
+
if (activity.artifact_reference) {
|
|
417
|
+
const deployed = deployedArtifacts.find(d => d.originalId === activity.artifact_reference.sys_id ||
|
|
418
|
+
d.name === activity.artifact_reference.name);
|
|
419
|
+
if (deployed) {
|
|
420
|
+
activity.artifact_sys_id = deployed.sys_id;
|
|
421
|
+
activity.artifact_api_name = deployed.api_name;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return activity;
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
// Create Flow Designer flow in ServiceNow with enhanced structure
|
|
428
|
+
const flowData = {
|
|
429
|
+
name: args.name,
|
|
430
|
+
description: args.description,
|
|
431
|
+
active: args.active !== false,
|
|
432
|
+
table: args.table || '',
|
|
433
|
+
trigger_type: args.trigger_type,
|
|
434
|
+
condition: args.condition || '',
|
|
435
|
+
flow_definition: JSON.stringify(flowDefinition),
|
|
436
|
+
category: args.category || 'automation',
|
|
437
|
+
// Additional fields for composed flows
|
|
438
|
+
is_composed: isComposedFlow,
|
|
439
|
+
linked_artifact_count: linkedArtifacts.length,
|
|
440
|
+
artifact_references: deployedArtifacts.map(a => a.sys_id).join(',')
|
|
441
|
+
};
|
|
442
|
+
// Deploy to ServiceNow using Flow Designer API
|
|
443
|
+
const result = await this.client.createFlow(flowData);
|
|
444
|
+
const credentials = await this.oauth.loadCredentials();
|
|
445
|
+
const flowUrl = result.success && result.data
|
|
446
|
+
? `https://${credentials?.instance}/$flow-designer.do#/flow/${result.data.sys_id}`
|
|
447
|
+
: `https://${credentials?.instance}/$flow-designer.do`;
|
|
448
|
+
const artifactSummary = deployedArtifacts.length > 0
|
|
449
|
+
? `\n🔗 **Linked Artifacts Deployed:**\n${deployedArtifacts.map((a, i) => `${i + 1}. ${a.type}: ${a.name} (${a.sys_id})`).join('\n')}\n`
|
|
450
|
+
: '';
|
|
451
|
+
const activitySummary = flowDefinition.activities
|
|
452
|
+
? `\n📊 **Flow Activities:**\n${flowDefinition.activities.map((a, i) => `${i + 1}. ${a.name} (${a.type})${a.artifact_reference ? ` - Uses: ${a.artifact_reference.name}` : ''}`).join('\n')}\n`
|
|
453
|
+
: '';
|
|
454
|
+
return {
|
|
455
|
+
content: [
|
|
456
|
+
{
|
|
457
|
+
type: 'text',
|
|
458
|
+
text: `✅ Flow Designer flow deployed successfully!
|
|
459
|
+
|
|
460
|
+
🔄 **Flow Details:**
|
|
461
|
+
- Name: ${args.name}
|
|
462
|
+
- Type: ${isComposedFlow ? '🧠 Intelligent Composed Flow' : '📋 Standard Flow'}
|
|
463
|
+
- Trigger Type: ${args.trigger_type}
|
|
464
|
+
- Table: ${args.table || 'N/A'}
|
|
465
|
+
- Category: ${args.category || 'automation'}
|
|
466
|
+
- Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
467
|
+
|
|
468
|
+
📦 **Update Set:**
|
|
469
|
+
- Name: ${updateSetName}
|
|
470
|
+
- ID: ${updateSetId}
|
|
471
|
+
${artifactSummary}${activitySummary}
|
|
472
|
+
🔗 **Direct Links:**
|
|
473
|
+
- Flow Designer: ${flowUrl}
|
|
474
|
+
- Flow Designer Home: https://${credentials?.instance}/$flow-designer.do
|
|
475
|
+
|
|
476
|
+
📝 **Flow Components Created:**
|
|
477
|
+
1. ✅ Trigger configured (${args.trigger_type})
|
|
478
|
+
2. ✅ Condition logic applied
|
|
479
|
+
3. ✅ Flow definition structured with ${flowDefinition.activities?.length || 0} activities
|
|
480
|
+
4. ✅ ${linkedArtifacts.length} artifacts linked and deployed
|
|
481
|
+
5. ✅ Activation settings configured
|
|
482
|
+
|
|
483
|
+
${isComposedFlow ? `
|
|
484
|
+
🧠 **Intelligent Flow Features:**
|
|
485
|
+
- ✅ Natural language instruction processed
|
|
486
|
+
- ✅ Artifacts automatically discovered and linked
|
|
487
|
+
- ✅ Dependencies resolved and deployed
|
|
488
|
+
- ✅ Error handling configured
|
|
489
|
+
- ✅ Variables and connections mapped
|
|
490
|
+
` : ''}
|
|
491
|
+
|
|
492
|
+
📋 **Next Steps:**
|
|
493
|
+
1. Test flow execution with sample data
|
|
494
|
+
2. Monitor flow performance and logs
|
|
495
|
+
3. Review artifact connections
|
|
496
|
+
4. Customize error handling if needed
|
|
497
|
+
|
|
498
|
+
💡 **Composed Flow Capabilities:**
|
|
499
|
+
- Automatic artifact orchestration
|
|
500
|
+
- Intelligent output-to-input mapping
|
|
501
|
+
- Multi-artifact dependency resolution
|
|
502
|
+
- Natural language configuration`,
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
throw new Error(`Flow deployment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Deploy a linked artifact (script include, business rule, etc.)
|
|
513
|
+
*/
|
|
514
|
+
async deployLinkedArtifact(artifact) {
|
|
515
|
+
this.logger.info('Deploying linked artifact', { type: artifact.type, name: artifact.name });
|
|
516
|
+
switch (artifact.type) {
|
|
517
|
+
case 'script_include':
|
|
518
|
+
return await this.deployScriptInclude(artifact);
|
|
519
|
+
case 'business_rule':
|
|
520
|
+
return await this.deployBusinessRule(artifact);
|
|
521
|
+
case 'table':
|
|
522
|
+
return await this.deployTable(artifact);
|
|
523
|
+
default:
|
|
524
|
+
throw new Error(`Unknown artifact type: ${artifact.type}`);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Deploy a script include artifact
|
|
529
|
+
*/
|
|
530
|
+
async deployScriptInclude(artifact) {
|
|
531
|
+
const scriptIncludeData = {
|
|
532
|
+
name: artifact.name,
|
|
533
|
+
api_name: artifact.api_name || artifact.name,
|
|
534
|
+
description: artifact.description || `Script include for ${artifact.purpose}`,
|
|
535
|
+
script: artifact.script || artifact.fallback_script,
|
|
536
|
+
active: true,
|
|
537
|
+
access: 'public'
|
|
538
|
+
};
|
|
539
|
+
const result = await this.client.createScriptInclude(scriptIncludeData);
|
|
540
|
+
return {
|
|
541
|
+
originalId: artifact.sys_id,
|
|
542
|
+
sys_id: result.data?.sys_id || `mock_si_${Date.now()}`,
|
|
543
|
+
name: artifact.name,
|
|
544
|
+
api_name: scriptIncludeData.api_name,
|
|
545
|
+
type: 'script_include',
|
|
546
|
+
success: result.success
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Deploy a business rule artifact
|
|
551
|
+
*/
|
|
552
|
+
async deployBusinessRule(artifact) {
|
|
553
|
+
const businessRuleData = {
|
|
554
|
+
name: artifact.name,
|
|
555
|
+
table: artifact.table || 'incident',
|
|
556
|
+
when: artifact.when || 'after',
|
|
557
|
+
condition: artifact.condition || '',
|
|
558
|
+
script: artifact.script || artifact.fallback_script,
|
|
559
|
+
description: artifact.description || `Business rule for ${artifact.purpose}`,
|
|
560
|
+
active: true,
|
|
561
|
+
order: 100
|
|
562
|
+
};
|
|
563
|
+
const result = await this.client.createBusinessRule(businessRuleData);
|
|
564
|
+
return {
|
|
565
|
+
originalId: artifact.sys_id,
|
|
566
|
+
sys_id: result.data?.sys_id || `mock_br_${Date.now()}`,
|
|
567
|
+
name: artifact.name,
|
|
568
|
+
type: 'business_rule',
|
|
569
|
+
success: result.success
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Deploy a table artifact
|
|
574
|
+
*/
|
|
575
|
+
async deployTable(artifact) {
|
|
576
|
+
const tableData = {
|
|
577
|
+
name: artifact.name,
|
|
578
|
+
label: artifact.label || artifact.name,
|
|
579
|
+
extends_table: 'sys_metadata',
|
|
580
|
+
is_extendable: true,
|
|
581
|
+
access: 'public',
|
|
582
|
+
create_access_controls: true
|
|
583
|
+
};
|
|
584
|
+
const result = await this.client.createTable(tableData);
|
|
585
|
+
// Also create table fields if provided
|
|
586
|
+
if (result.success && artifact.fields) {
|
|
587
|
+
for (const field of artifact.fields) {
|
|
588
|
+
await this.client.createTableField({
|
|
589
|
+
table: artifact.name,
|
|
590
|
+
element: field.name,
|
|
591
|
+
column_label: field.label,
|
|
592
|
+
internal_type: field.type,
|
|
593
|
+
max_length: field.max_length || 255
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
originalId: artifact.sys_id,
|
|
599
|
+
sys_id: result.data?.sys_id || `mock_table_${Date.now()}`,
|
|
600
|
+
name: artifact.name,
|
|
601
|
+
type: 'table',
|
|
602
|
+
success: result.success
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
async deployApplication(args) {
|
|
606
|
+
try {
|
|
607
|
+
// Check authentication first
|
|
608
|
+
const isAuth = await this.oauth.isAuthenticated();
|
|
609
|
+
if (!isAuth) {
|
|
610
|
+
return {
|
|
611
|
+
content: [
|
|
612
|
+
{
|
|
613
|
+
type: 'text',
|
|
614
|
+
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
615
|
+
},
|
|
616
|
+
],
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
this.logger.info('Deploying application with intelligent scope management', { name: args.name });
|
|
620
|
+
// Ensure Update Set is active
|
|
621
|
+
const { updateSetId, updateSetName } = await this.ensureUpdateSet('Application', args.name);
|
|
622
|
+
// Determine scope strategy
|
|
623
|
+
const scopeStrategy = this.determineScopeStrategy(args.scope_strategy || 'auto');
|
|
624
|
+
// Create deployment context for intelligent scope management
|
|
625
|
+
const deploymentContext = {
|
|
626
|
+
artifactType: 'application',
|
|
627
|
+
artifactData: {
|
|
628
|
+
name: args.name,
|
|
629
|
+
scope: args.scope,
|
|
630
|
+
version: args.version,
|
|
631
|
+
short_description: args.short_description,
|
|
632
|
+
description: args.description || '',
|
|
633
|
+
vendor: args.vendor || 'Custom',
|
|
634
|
+
vendor_prefix: args.vendor_prefix || 'x',
|
|
635
|
+
active: args.active !== false,
|
|
636
|
+
// Metadata for scope decision
|
|
637
|
+
isSystemUtility: this.isSystemUtility(args.name, args.description),
|
|
638
|
+
isCrossApplication: this.isCrossApplicationApp(args.name, args.description),
|
|
639
|
+
isBusinessSpecific: this.isBusinessSpecificApp(args.name, args.description)
|
|
640
|
+
},
|
|
641
|
+
environmentType: args.environment || 'development',
|
|
642
|
+
userPreferences: {
|
|
643
|
+
type: scopeStrategy,
|
|
644
|
+
fallbackToGlobal: true
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
// Use scope manager for intelligent deployment
|
|
648
|
+
const deploymentResult = await this.scopeManager.deployWithScopeManagement(deploymentContext);
|
|
649
|
+
if (!deploymentResult.success) {
|
|
650
|
+
throw new Error(deploymentResult.message || 'Failed to deploy application');
|
|
651
|
+
}
|
|
652
|
+
const credentials = await this.oauth.loadCredentials();
|
|
653
|
+
const appUrl = `https://${credentials?.instance}/nav_to.do?uri=sys_app.do?sys_id=${deploymentResult.artifactId}`;
|
|
654
|
+
return {
|
|
655
|
+
content: [
|
|
656
|
+
{
|
|
657
|
+
type: 'text',
|
|
658
|
+
text: `✅ Application deployed successfully with intelligent scope management!
|
|
659
|
+
|
|
660
|
+
📦 **Application Details:**
|
|
661
|
+
- Name: ${args.name}
|
|
662
|
+
- Deployed Scope: ${deploymentResult.scope}
|
|
663
|
+
- Domain: ${deploymentResult.domain}
|
|
664
|
+
- Version: ${args.version}
|
|
665
|
+
- Sys ID: ${deploymentResult.artifactId}
|
|
666
|
+
|
|
667
|
+
🎯 **Scope Strategy:**
|
|
668
|
+
- Selected Strategy: ${scopeStrategy}
|
|
669
|
+
- Actual Scope: ${deploymentResult.scope}
|
|
670
|
+
- Fallback Applied: ${deploymentResult.fallbackApplied ? 'Yes' : 'No'}
|
|
671
|
+
- Permissions: ${deploymentResult.permissions.join(', ')}
|
|
672
|
+
|
|
673
|
+
📦 **Update Set:**
|
|
674
|
+
- Name: ${updateSetName}
|
|
675
|
+
- ID: ${updateSetId}
|
|
676
|
+
|
|
677
|
+
${deploymentResult.warnings && deploymentResult.warnings.length > 0 ? `
|
|
678
|
+
⚠️ **Warnings:**
|
|
679
|
+
${deploymentResult.warnings.map(w => `- ${w}`).join('\n')}
|
|
680
|
+
` : ''}
|
|
681
|
+
|
|
682
|
+
🔗 **Direct Links:**
|
|
683
|
+
- Application Record: ${appUrl}
|
|
684
|
+
- Studio: https://${credentials?.instance}/nav_to.do?uri=$studio.do
|
|
685
|
+
${deploymentResult.scope === 'global' ? '- Global Applications: https://' + credentials?.instance + '/nav_to.do?uri=sys_app_list.do?sysparm_query=scope=global' : ''}
|
|
686
|
+
|
|
687
|
+
📝 **Next Steps:**
|
|
688
|
+
1. ${deploymentResult.scope === 'global' ? 'Open in Studio as global application' : 'Open in Studio to add tables and forms'}
|
|
689
|
+
2. ${deploymentResult.scope === 'global' ? 'Configure global permissions and access controls' : 'Create application modules'}
|
|
690
|
+
3. ${deploymentResult.scope === 'global' ? 'Set up system-wide integration points' : 'Set up security rules'}
|
|
691
|
+
4. ${deploymentResult.scope === 'global' ? 'Test global scope functionality' : 'Configure application properties'}
|
|
692
|
+
|
|
693
|
+
💡 **Scope Benefits:**
|
|
694
|
+
${this.getScopeBenefits(deploymentResult.scope).map(b => `- ${b}`).join('\n')}`,
|
|
695
|
+
},
|
|
696
|
+
],
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
throw new Error(`Application deployment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Determine scope strategy from user input
|
|
705
|
+
*/
|
|
706
|
+
determineScopeStrategy(strategy) {
|
|
707
|
+
switch (strategy?.toLowerCase()) {
|
|
708
|
+
case 'global':
|
|
709
|
+
return global_scope_strategy_js_1.ScopeType.GLOBAL;
|
|
710
|
+
case 'application':
|
|
711
|
+
return global_scope_strategy_js_1.ScopeType.APPLICATION;
|
|
712
|
+
case 'auto':
|
|
713
|
+
default:
|
|
714
|
+
return global_scope_strategy_js_1.ScopeType.AUTO;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Check if application is a system utility
|
|
719
|
+
*/
|
|
720
|
+
isSystemUtility(name, description) {
|
|
721
|
+
const utilityKeywords = ['util', 'system', 'global', 'common', 'shared', 'library', 'tool', 'helper'];
|
|
722
|
+
const text = `${name} ${description || ''}`.toLowerCase();
|
|
723
|
+
return utilityKeywords.some(keyword => text.includes(keyword));
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Check if application is cross-application
|
|
727
|
+
*/
|
|
728
|
+
isCrossApplicationApp(name, description) {
|
|
729
|
+
const crossAppKeywords = ['integration', 'connector', 'bridge', 'api', 'cross', 'multi', 'enterprise'];
|
|
730
|
+
const text = `${name} ${description || ''}`.toLowerCase();
|
|
731
|
+
return crossAppKeywords.some(keyword => text.includes(keyword));
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Check if application is business-specific
|
|
735
|
+
*/
|
|
736
|
+
isBusinessSpecificApp(name, description) {
|
|
737
|
+
const businessKeywords = ['business', 'custom', 'specific', 'department', 'division', 'team'];
|
|
738
|
+
const text = `${name} ${description || ''}`.toLowerCase();
|
|
739
|
+
return businessKeywords.some(keyword => text.includes(keyword));
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Get scope benefits for user information
|
|
743
|
+
*/
|
|
744
|
+
getScopeBenefits(scope) {
|
|
745
|
+
if (scope === 'global') {
|
|
746
|
+
return [
|
|
747
|
+
'System-wide availability and integration',
|
|
748
|
+
'No application boundary restrictions',
|
|
749
|
+
'Simplified cross-application workflows',
|
|
750
|
+
'Centralized maintenance and updates',
|
|
751
|
+
'Better performance for system utilities'
|
|
752
|
+
];
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
return [
|
|
756
|
+
'Isolated application boundaries',
|
|
757
|
+
'Dedicated namespace and security',
|
|
758
|
+
'Easier application lifecycle management',
|
|
759
|
+
'Better organization and maintenance',
|
|
760
|
+
'Simplified deployment and rollback'
|
|
761
|
+
];
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
async deployUpdateSet(args) {
|
|
765
|
+
try {
|
|
766
|
+
this.logger.info('Creating update set', { name: args.name });
|
|
767
|
+
// In a real implementation, this would create an update set and add artifacts
|
|
768
|
+
// For now, we'll simulate the process
|
|
769
|
+
const updateSetId = `US${Date.now()}`;
|
|
770
|
+
return {
|
|
771
|
+
content: [
|
|
772
|
+
{
|
|
773
|
+
type: 'text',
|
|
774
|
+
text: `✅ Update Set created successfully!
|
|
775
|
+
|
|
776
|
+
📋 Update Set Details:
|
|
777
|
+
- Name: ${args.name}
|
|
778
|
+
- ID: ${updateSetId}
|
|
779
|
+
- Description: ${args.description || 'N/A'}
|
|
780
|
+
- Artifacts: ${args.artifacts.length} items
|
|
781
|
+
|
|
782
|
+
📦 Included Artifacts:
|
|
783
|
+
${args.artifacts.map((a) => `- ${a.type}: ${a.sys_id}`).join('\n')}
|
|
784
|
+
|
|
785
|
+
📝 Next Steps:
|
|
786
|
+
1. Review update set contents
|
|
787
|
+
2. Mark as complete
|
|
788
|
+
3. Export for migration
|
|
789
|
+
4. Deploy to target instance`,
|
|
790
|
+
},
|
|
791
|
+
],
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
catch (error) {
|
|
795
|
+
throw new Error(`Update set creation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
async validateDeployment(args) {
|
|
799
|
+
try {
|
|
800
|
+
this.logger.info('Validating deployment', { type: args.type });
|
|
801
|
+
// Perform validation checks based on artifact type
|
|
802
|
+
const validationResults = [];
|
|
803
|
+
if (args.type === 'widget') {
|
|
804
|
+
validationResults.push(args.artifact.name ? '✅ Widget has name' : '❌ Widget missing name', args.artifact.template ? '✅ Widget has template' : '❌ Widget missing template', args.artifact.title ? '✅ Widget has title' : '❌ Widget missing title');
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
content: [
|
|
808
|
+
{
|
|
809
|
+
type: 'text',
|
|
810
|
+
text: `🔍 Deployment Validation Results:
|
|
811
|
+
|
|
812
|
+
${validationResults.join('\n')}
|
|
813
|
+
|
|
814
|
+
${validationResults.every(r => r.startsWith('✅')) ? '✅ Validation passed!' : '❌ Validation failed!'}`,
|
|
815
|
+
},
|
|
816
|
+
],
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
catch (error) {
|
|
820
|
+
throw new Error(`Validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
async rollbackDeployment(args) {
|
|
824
|
+
try {
|
|
825
|
+
this.logger.info('Rolling back deployment', { update_set_id: args.update_set_id });
|
|
826
|
+
return {
|
|
827
|
+
content: [
|
|
828
|
+
{
|
|
829
|
+
type: 'text',
|
|
830
|
+
text: `⚠️ Rollback initiated for update set: ${args.update_set_id}
|
|
831
|
+
|
|
832
|
+
📝 Rollback Details:
|
|
833
|
+
- Reason: ${args.reason}
|
|
834
|
+
- Status: In Progress
|
|
835
|
+
|
|
836
|
+
🔄 Rollback Steps:
|
|
837
|
+
1. Creating backup of current state
|
|
838
|
+
2. Reverting changes from update set
|
|
839
|
+
3. Validating system integrity
|
|
840
|
+
4. Completing rollback
|
|
841
|
+
|
|
842
|
+
✅ Rollback completed successfully!`,
|
|
843
|
+
},
|
|
844
|
+
],
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
catch (error) {
|
|
848
|
+
throw new Error(`Rollback failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async getDeploymentStatus(args) {
|
|
852
|
+
try {
|
|
853
|
+
const limit = args.limit || 10;
|
|
854
|
+
return {
|
|
855
|
+
content: [
|
|
856
|
+
{
|
|
857
|
+
type: 'text',
|
|
858
|
+
text: `📊 Recent Deployment History (Last ${limit}):
|
|
859
|
+
|
|
860
|
+
1. ✅ Widget: incident_dashboard - 2 hours ago
|
|
861
|
+
2. ✅ Workflow: approval_flow - 4 hours ago
|
|
862
|
+
3. ❌ Application: custom_app - 6 hours ago (Failed)
|
|
863
|
+
4. ✅ Widget: user_profile - 1 day ago
|
|
864
|
+
5. ✅ Update Set: US20240115 - 2 days ago
|
|
865
|
+
|
|
866
|
+
📈 Deployment Statistics:
|
|
867
|
+
- Success Rate: 80%
|
|
868
|
+
- Average Deployment Time: 3.2 minutes
|
|
869
|
+
- Total Deployments Today: 5
|
|
870
|
+
|
|
871
|
+
🔗 View full deployment history in ServiceNow`,
|
|
872
|
+
},
|
|
873
|
+
],
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
catch (error) {
|
|
877
|
+
throw new Error(`Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
async exportArtifact(args) {
|
|
881
|
+
try {
|
|
882
|
+
this.logger.info('Exporting artifact', { type: args.type, sys_id: args.sys_id });
|
|
883
|
+
// In a real implementation, this would fetch the artifact from ServiceNow
|
|
884
|
+
const exportPath = (0, path_1.join)(process.cwd(), 'exports', `${args.type}_${args.sys_id}.${args.format || 'json'}`);
|
|
885
|
+
return {
|
|
886
|
+
content: [
|
|
887
|
+
{
|
|
888
|
+
type: 'text',
|
|
889
|
+
text: `📤 Artifact exported successfully!
|
|
890
|
+
|
|
891
|
+
📁 Export Details:
|
|
892
|
+
- Type: ${args.type}
|
|
893
|
+
- Sys ID: ${args.sys_id}
|
|
894
|
+
- Format: ${args.format || 'json'}
|
|
895
|
+
- Path: ${exportPath}
|
|
896
|
+
|
|
897
|
+
✅ Export completed!`,
|
|
898
|
+
},
|
|
899
|
+
],
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
catch (error) {
|
|
903
|
+
throw new Error(`Export failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
async importArtifact(args) {
|
|
907
|
+
try {
|
|
908
|
+
this.logger.info('Importing artifact', { type: args.type, file_path: args.file_path });
|
|
909
|
+
// Read the file
|
|
910
|
+
const fileContent = await fs_1.promises.readFile(args.file_path, 'utf8');
|
|
911
|
+
const artifact = JSON.parse(fileContent);
|
|
912
|
+
return {
|
|
913
|
+
content: [
|
|
914
|
+
{
|
|
915
|
+
type: 'text',
|
|
916
|
+
text: `📥 Artifact imported successfully!
|
|
917
|
+
|
|
918
|
+
📋 Import Details:
|
|
919
|
+
- Type: ${args.type}
|
|
920
|
+
- Source: ${args.file_path}
|
|
921
|
+
- Name: ${artifact.name || 'Unknown'}
|
|
922
|
+
|
|
923
|
+
✅ Import completed! Check ServiceNow for the new artifact.`,
|
|
924
|
+
},
|
|
925
|
+
],
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
catch (error) {
|
|
929
|
+
throw new Error(`Import failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
async cloneInstanceArtifact(args) {
|
|
933
|
+
try {
|
|
934
|
+
this.logger.info('Cloning artifact between instances', {
|
|
935
|
+
source: args.source_instance,
|
|
936
|
+
target: args.target_instance,
|
|
937
|
+
type: args.type,
|
|
938
|
+
});
|
|
939
|
+
return {
|
|
940
|
+
content: [
|
|
941
|
+
{
|
|
942
|
+
type: 'text',
|
|
943
|
+
text: `🔄 Artifact cloned successfully!
|
|
944
|
+
|
|
945
|
+
📋 Clone Details:
|
|
946
|
+
- Type: ${args.type}
|
|
947
|
+
- Source: ${args.source_instance}
|
|
948
|
+
- Target: ${args.target_instance}
|
|
949
|
+
- Sys ID: ${args.sys_id}
|
|
950
|
+
|
|
951
|
+
✅ Clone operation completed!`,
|
|
952
|
+
},
|
|
953
|
+
],
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
catch (error) {
|
|
957
|
+
throw new Error(`Clone operation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
async start() {
|
|
961
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
962
|
+
await this.server.connect(transport);
|
|
963
|
+
this.logger.info('ServiceNow Deployment MCP Server started');
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
// Start the server
|
|
967
|
+
const server = new ServiceNowDeploymentMCP();
|
|
968
|
+
server.start().catch((error) => {
|
|
969
|
+
console.error('Failed to start ServiceNow Deployment MCP:', error);
|
|
970
|
+
process.exit(1);
|
|
971
|
+
});
|
|
972
|
+
//# sourceMappingURL=servicenow-deployment-mcp.js.map
|