snow-flow 3.5.3 → 3.5.5
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/.mcp.json
CHANGED
|
@@ -194,6 +194,18 @@
|
|
|
194
194
|
"SNOW_CLIENT_SECRET": "${SNOW_CLIENT_SECRET}"
|
|
195
195
|
}
|
|
196
196
|
},
|
|
197
|
+
"servicenow-local-development": {
|
|
198
|
+
"command": "node",
|
|
199
|
+
"args": [
|
|
200
|
+
"/Users/nielsvanderwerf/Projects/snow-flow-dev/snow-flow/dist/mcp/servicenow-local-development-mcp.js"
|
|
201
|
+
],
|
|
202
|
+
"description": "Local development bridge for Claude Code - pull any ServiceNow artifact to local files with native tool integration (snow_pull_artifact, snow_push_artifact, snow_validate_artifact_coherence), smart field chunking for large artifacts, ES5 validation, coherence checking, 12+ artifact types support",
|
|
203
|
+
"env": {
|
|
204
|
+
"SNOW_INSTANCE": "${SNOW_INSTANCE}",
|
|
205
|
+
"SNOW_CLIENT_ID": "${SNOW_CLIENT_ID}",
|
|
206
|
+
"SNOW_CLIENT_SECRET": "${SNOW_CLIENT_SECRET}"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
197
209
|
"snow-flow": {
|
|
198
210
|
"command": "node",
|
|
199
211
|
"args": [
|
package/.mcp.json.template
CHANGED
|
@@ -194,6 +194,18 @@
|
|
|
194
194
|
"SNOW_CLIENT_SECRET": "{{SNOW_CLIENT_SECRET}}"
|
|
195
195
|
}
|
|
196
196
|
},
|
|
197
|
+
"servicenow-local-development": {
|
|
198
|
+
"command": "node",
|
|
199
|
+
"args": [
|
|
200
|
+
"{{PROJECT_ROOT}}/dist/mcp/servicenow-local-development-mcp.js"
|
|
201
|
+
],
|
|
202
|
+
"description": "Local development bridge for Claude Code - pull any ServiceNow artifact to local files with native tool integration (snow_pull_artifact, snow_push_artifact, snow_validate_artifact_coherence), smart field chunking for large artifacts, ES5 validation, coherence checking, 12+ artifact types support",
|
|
203
|
+
"env": {
|
|
204
|
+
"SNOW_INSTANCE": "{{SNOW_INSTANCE}}",
|
|
205
|
+
"SNOW_CLIENT_ID": "{{SNOW_CLIENT_ID}}",
|
|
206
|
+
"SNOW_CLIENT_SECRET": "{{SNOW_CLIENT_SECRET}}"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
197
209
|
"snow-flow": {
|
|
198
210
|
"command": "node",
|
|
199
211
|
"args": [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
/**
|
|
2
3
|
* ServiceNow Local Development MCP Server
|
|
3
4
|
*
|
|
@@ -7,42 +8,5 @@
|
|
|
7
8
|
*
|
|
8
9
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
-
export declare class ServiceNowLocalDevelopmentMCP extends BaseMCPServer {
|
|
12
|
-
private syncManager;
|
|
13
|
-
constructor();
|
|
14
|
-
protected initializeTools(): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* DYNAMIC pull artifact to local files
|
|
17
|
-
*/
|
|
18
|
-
private pullArtifact;
|
|
19
|
-
/**
|
|
20
|
-
* Push artifact changes back to ServiceNow
|
|
21
|
-
*/
|
|
22
|
-
private pushArtifact;
|
|
23
|
-
/**
|
|
24
|
-
* Get sync status
|
|
25
|
-
*/
|
|
26
|
-
private getSyncStatus;
|
|
27
|
-
/**
|
|
28
|
-
* Cleanup local files
|
|
29
|
-
*/
|
|
30
|
-
private cleanup;
|
|
31
|
-
/**
|
|
32
|
-
* List supported artifact types
|
|
33
|
-
*/
|
|
34
|
-
private listSupportedArtifacts;
|
|
35
|
-
/**
|
|
36
|
-
* Validate artifact coherence
|
|
37
|
-
*/
|
|
38
|
-
private validateCoherence;
|
|
39
|
-
/**
|
|
40
|
-
* Convert modern JS to ES5
|
|
41
|
-
*/
|
|
42
|
-
private convertToES5;
|
|
43
|
-
/**
|
|
44
|
-
* Search in widgets (like Claude Code search)
|
|
45
|
-
*/
|
|
46
|
-
private searchInWidgets;
|
|
47
|
-
}
|
|
11
|
+
export {};
|
|
48
12
|
//# sourceMappingURL=servicenow-local-development-mcp.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
/**
|
|
3
4
|
* ServiceNow Local Development MCP Server
|
|
@@ -8,563 +9,425 @@
|
|
|
8
9
|
*
|
|
9
10
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
10
11
|
*/
|
|
11
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
-
}
|
|
17
|
-
Object.defineProperty(o, k2, desc);
|
|
18
|
-
}) : (function(o, m, k, k2) {
|
|
19
|
-
if (k2 === undefined) k2 = k;
|
|
20
|
-
o[k2] = m[k];
|
|
21
|
-
}));
|
|
22
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
-
}) : function(o, v) {
|
|
25
|
-
o["default"] = v;
|
|
26
|
-
});
|
|
27
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
-
var ownKeys = function(o) {
|
|
29
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
-
var ar = [];
|
|
31
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
-
return ar;
|
|
33
|
-
};
|
|
34
|
-
return ownKeys(o);
|
|
35
|
-
};
|
|
36
|
-
return function (mod) {
|
|
37
|
-
if (mod && mod.__esModule) return mod;
|
|
38
|
-
var result = {};
|
|
39
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
-
__setModuleDefault(result, mod);
|
|
41
|
-
return result;
|
|
42
|
-
};
|
|
43
|
-
})();
|
|
44
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
class ServiceNowLocalDevelopmentMCP extends
|
|
13
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
14
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
15
|
+
const enhanced_base_mcp_server_js_1 = require("./shared/enhanced-base-mcp-server.js");
|
|
16
|
+
const artifact_local_sync_js_1 = require("../utils/artifact-local-sync.js");
|
|
17
|
+
const artifact_registry_js_1 = require("../utils/artifact-sync/artifact-registry.js");
|
|
18
|
+
class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.EnhancedBaseMCPServer {
|
|
51
19
|
constructor() {
|
|
52
20
|
super('servicenow-local-development', '1.0.0');
|
|
53
|
-
|
|
21
|
+
// Initialize after client is available
|
|
22
|
+
this.setupSyncManager();
|
|
23
|
+
this.setupHandlers();
|
|
24
|
+
}
|
|
25
|
+
setupSyncManager() {
|
|
26
|
+
// Initialize sync manager with the client from enhanced base server
|
|
27
|
+
this.syncManager = new artifact_local_sync_js_1.ArtifactLocalSync(this.client);
|
|
28
|
+
this.logger.info('🔧 Local sync manager initialized');
|
|
54
29
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
30
|
+
setupHandlers() {
|
|
31
|
+
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
32
|
+
tools: [
|
|
33
|
+
{
|
|
34
|
+
name: 'snow_pull_artifact',
|
|
35
|
+
description: `Pull ANY ServiceNow artifact to local files for editing with Claude Code's native tools. Automatically detects the artifact type and creates appropriate files based on the artifact registry. Supports: ${(0, artifact_registry_js_1.getSupportedTables)().map(t => (0, artifact_registry_js_1.getTableDisplayName)(t)).join(', ')}`,
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
sys_id: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
description: 'Artifact sys_id to pull'
|
|
42
|
+
},
|
|
43
|
+
table: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Optional: Specify table name if known for faster processing',
|
|
46
|
+
enum: (0, artifact_registry_js_1.getSupportedTables)()
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
required: ['sys_id']
|
|
73
50
|
}
|
|
74
51
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
52
|
+
{
|
|
53
|
+
name: 'snow_push_artifact',
|
|
54
|
+
description: 'Push local artifact changes back to ServiceNow with validation and coherence checking',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
sys_id: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Artifact sys_id to push back'
|
|
61
|
+
},
|
|
62
|
+
force: {
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
description: 'Force push despite validation warnings',
|
|
65
|
+
default: false
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
required: ['sys_id']
|
|
89
69
|
}
|
|
90
70
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
description: 'Script Include sys_id'
|
|
71
|
+
{
|
|
72
|
+
name: 'snow_validate_artifact_coherence',
|
|
73
|
+
description: 'Validate coherence and relationships between artifact components (e.g., widget HTML-client-server relationships)',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {
|
|
77
|
+
sys_id: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description: 'Artifact sys_id to validate'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
required: ['sys_id']
|
|
104
83
|
}
|
|
105
84
|
},
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
inputSchema: {
|
|
114
|
-
type: 'object',
|
|
115
|
-
properties: {
|
|
116
|
-
sys_id: {
|
|
117
|
-
type: 'string',
|
|
118
|
-
description: 'Business Rule sys_id'
|
|
85
|
+
{
|
|
86
|
+
name: 'snow_list_supported_artifacts',
|
|
87
|
+
description: 'List all supported artifact types for local synchronization',
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {},
|
|
91
|
+
additionalProperties: false
|
|
119
92
|
}
|
|
120
93
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
type: 'object',
|
|
133
|
-
properties: {
|
|
134
|
-
sys_id: {
|
|
135
|
-
type: 'string',
|
|
136
|
-
description: 'Artifact sys_id to push changes for'
|
|
137
|
-
},
|
|
138
|
-
force: {
|
|
139
|
-
type: 'boolean',
|
|
140
|
-
description: 'Force push even with validation warnings',
|
|
141
|
-
default: false
|
|
94
|
+
{
|
|
95
|
+
name: 'snow_sync_status',
|
|
96
|
+
description: 'Check sync status of local artifacts',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
sys_id: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
description: 'Optional: Check specific artifact, or all if omitted'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
142
105
|
}
|
|
143
106
|
},
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
107
|
+
{
|
|
108
|
+
name: 'snow_sync_cleanup',
|
|
109
|
+
description: 'Clean up local artifact files after successful sync',
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {
|
|
113
|
+
sys_id: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
description: 'Artifact sys_id to clean up'
|
|
116
|
+
},
|
|
117
|
+
force: {
|
|
118
|
+
type: 'boolean',
|
|
119
|
+
description: 'Force cleanup even with unsaved changes',
|
|
120
|
+
default: false
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
required: ['sys_id']
|
|
158
124
|
}
|
|
159
125
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
handler: async (args) => this.getSyncStatus(args)
|
|
178
|
-
});
|
|
179
|
-
this.addTool({
|
|
180
|
-
name: 'snow_sync_cleanup',
|
|
181
|
-
description: 'Clean up local files after successful sync',
|
|
182
|
-
inputSchema: {
|
|
183
|
-
type: 'object',
|
|
184
|
-
properties: {
|
|
185
|
-
sys_id: {
|
|
186
|
-
type: 'string',
|
|
187
|
-
description: 'Artifact sys_id to clean up'
|
|
188
|
-
},
|
|
189
|
-
force: {
|
|
190
|
-
type: 'boolean',
|
|
191
|
-
description: 'Force cleanup even with unsaved changes',
|
|
192
|
-
default: false
|
|
126
|
+
{
|
|
127
|
+
name: 'snow_convert_to_es5',
|
|
128
|
+
description: 'Convert modern JavaScript code to ES5 for ServiceNow compatibility',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {
|
|
132
|
+
code: {
|
|
133
|
+
type: 'string',
|
|
134
|
+
description: 'JavaScript code to convert to ES5'
|
|
135
|
+
},
|
|
136
|
+
context: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
description: 'Context: server_script, client_script, business_rule, etc.',
|
|
139
|
+
enum: ['server_script', 'client_script', 'business_rule', 'script_include', 'ui_script']
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
required: ['code']
|
|
193
143
|
}
|
|
194
144
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
this.addTool({
|
|
210
|
-
name: 'snow_validate_artifact_coherence',
|
|
211
|
-
description: 'Validate artifact based on its type-specific coherence rules',
|
|
212
|
-
inputSchema: {
|
|
213
|
-
type: 'object',
|
|
214
|
-
properties: {
|
|
215
|
-
sys_id: {
|
|
216
|
-
type: 'string',
|
|
217
|
-
description: 'Artifact sys_id to validate'
|
|
145
|
+
// Legacy compatibility tools
|
|
146
|
+
{
|
|
147
|
+
name: 'snow_pull_widget',
|
|
148
|
+
description: 'Pull a ServiceNow widget to local files (legacy - use snow_pull_artifact instead)',
|
|
149
|
+
inputSchema: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
sys_id: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'Widget sys_id to pull'
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
required: ['sys_id']
|
|
218
158
|
}
|
|
219
159
|
},
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
description: 'Path to JavaScript file to convert'
|
|
233
|
-
},
|
|
234
|
-
inline_code: {
|
|
235
|
-
type: 'string',
|
|
236
|
-
description: 'Or provide code directly'
|
|
160
|
+
{
|
|
161
|
+
name: 'snow_push_widget',
|
|
162
|
+
description: 'Push widget changes back to ServiceNow (legacy - use snow_push_artifact instead)',
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
sys_id: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
description: 'Widget sys_id to push'
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
required: ['sys_id']
|
|
237
172
|
}
|
|
238
173
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
174
|
+
]
|
|
175
|
+
}));
|
|
176
|
+
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
177
|
+
const { name, arguments: args } = request.params;
|
|
178
|
+
try {
|
|
179
|
+
this.logger.info(`🔧 Executing tool: ${name}`, args);
|
|
180
|
+
let result;
|
|
181
|
+
switch (name) {
|
|
182
|
+
case 'snow_pull_artifact':
|
|
183
|
+
result = await this.pullArtifact(args);
|
|
184
|
+
break;
|
|
185
|
+
case 'snow_push_artifact':
|
|
186
|
+
result = await this.pushArtifact(args);
|
|
187
|
+
break;
|
|
188
|
+
case 'snow_validate_artifact_coherence':
|
|
189
|
+
result = await this.validateArtifactCoherence(args);
|
|
190
|
+
break;
|
|
191
|
+
case 'snow_sync_status':
|
|
192
|
+
result = await this.getSyncStatus(args);
|
|
193
|
+
break;
|
|
194
|
+
case 'snow_list_supported_artifacts':
|
|
195
|
+
result = await this.listSupportedArtifacts(args);
|
|
196
|
+
break;
|
|
197
|
+
case 'snow_sync_cleanup':
|
|
198
|
+
result = await this.syncCleanup(args);
|
|
199
|
+
break;
|
|
200
|
+
case 'snow_convert_to_es5':
|
|
201
|
+
result = await this.convertToES5(args);
|
|
202
|
+
break;
|
|
203
|
+
// Legacy compatibility
|
|
204
|
+
case 'snow_pull_widget':
|
|
205
|
+
result = await this.pullWidget(args);
|
|
206
|
+
break;
|
|
207
|
+
case 'snow_push_widget':
|
|
208
|
+
result = await this.pushWidget(args);
|
|
209
|
+
break;
|
|
210
|
+
default:
|
|
211
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
212
|
+
}
|
|
213
|
+
this.logger.info(`✅ Tool ${name} completed successfully`);
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
218
|
+
this.logger.error(`❌ Tool ${name} failed: ${errorMessage}`);
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{
|
|
222
|
+
type: 'text',
|
|
223
|
+
text: `Error executing ${name}: ${errorMessage}`
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
};
|
|
227
|
+
}
|
|
267
228
|
});
|
|
268
229
|
}
|
|
269
|
-
/**
|
|
270
|
-
* DYNAMIC pull artifact to local files
|
|
271
|
-
*/
|
|
272
230
|
async pullArtifact(args) {
|
|
231
|
+
const { sys_id, table } = args;
|
|
273
232
|
try {
|
|
274
233
|
let artifact;
|
|
275
|
-
if (
|
|
276
|
-
//
|
|
277
|
-
artifact = await this.syncManager.pullArtifact(
|
|
234
|
+
if (table) {
|
|
235
|
+
// Use specified table
|
|
236
|
+
artifact = await this.syncManager.pullArtifact(table, sys_id);
|
|
278
237
|
}
|
|
279
238
|
else {
|
|
280
239
|
// Auto-detect table
|
|
281
|
-
artifact = await this.syncManager.pullArtifactBySysId(
|
|
240
|
+
artifact = await this.syncManager.pullArtifactBySysId(sys_id);
|
|
282
241
|
}
|
|
283
|
-
const config = artifact.artifactConfig;
|
|
284
|
-
const hasES5 = config?.fieldMappings.some(fm => fm.validateES5);
|
|
285
|
-
const hasCoherence = config?.coherenceRules && config.coherenceRules.length > 0;
|
|
286
|
-
const message = `
|
|
287
|
-
✅ **${artifact.type} pulled to local files successfully!**
|
|
288
|
-
|
|
289
|
-
📁 **Location:** \`${artifact.localPath}\`
|
|
290
|
-
|
|
291
|
-
📄 **Files created:**
|
|
292
|
-
${artifact.files.map(f => `- **${f.filename}** (${f.type})`).join('\n')}
|
|
293
|
-
|
|
294
|
-
🎯 **Now you can:**
|
|
295
|
-
1. Use Claude Code's native tools to edit these files
|
|
296
|
-
2. Search across files with full regex support
|
|
297
|
-
3. Multi-file operations and refactoring
|
|
298
|
-
4. Use all VS Code/editor features
|
|
299
|
-
5. When done, run \`snow_push_artifact\` to sync back
|
|
300
|
-
|
|
301
|
-
${hasES5 ? `⚠️ **ES5 Requirement:**
|
|
302
|
-
- Server-side scripts MUST be ES5 only
|
|
303
|
-
- No const/let/arrow functions/template literals
|
|
304
|
-
- Use var and function() syntax only
|
|
305
|
-
|
|
306
|
-
` : ''}
|
|
307
|
-
${hasCoherence ? `🔗 **Coherence Rules:**
|
|
308
|
-
- This artifact has validation rules that will be checked
|
|
309
|
-
- Run \`snow_validate_artifact_coherence\` to test
|
|
310
|
-
- Push will warn about any violations
|
|
311
|
-
|
|
312
|
-
` : ''}
|
|
313
|
-
📝 **Edit the files now, then push changes back to ServiceNow!**
|
|
314
|
-
`;
|
|
315
242
|
return {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: 'text',
|
|
246
|
+
text: `✅ Successfully pulled ${artifact.type} to local files at: ${artifact.localPath}\n\n📁 Files created:\n${artifact.files.map(f => ` - ${f.filename} (${f.type})`).join('\n')}\n\n💡 You can now use Claude Code's native tools to edit these files!`
|
|
247
|
+
}
|
|
248
|
+
]
|
|
319
249
|
};
|
|
320
250
|
}
|
|
321
251
|
catch (error) {
|
|
322
|
-
|
|
252
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
253
|
+
return {
|
|
254
|
+
content: [
|
|
255
|
+
{
|
|
256
|
+
type: 'text',
|
|
257
|
+
text: `❌ Failed to pull artifact: ${errorMessage}`
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
};
|
|
323
261
|
}
|
|
324
262
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Push artifact changes back to ServiceNow
|
|
327
|
-
*/
|
|
328
263
|
async pushArtifact(args) {
|
|
264
|
+
const { sys_id, force = false } = args;
|
|
329
265
|
try {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
output += '**Errors:**\n' + r.errors.map(e => `- ❌ ${e}`).join('\n') + '\n';
|
|
342
|
-
}
|
|
343
|
-
if (r.warnings.length > 0) {
|
|
344
|
-
output += '**Warnings:**\n' + r.warnings.map(w => `- ⚠️ ${w}`).join('\n') + '\n';
|
|
345
|
-
}
|
|
346
|
-
if (r.hints.length > 0) {
|
|
347
|
-
output += '**Hints:**\n' + r.hints.map(h => `- 💡 ${h}`).join('\n');
|
|
348
|
-
}
|
|
349
|
-
return output;
|
|
350
|
-
}).join('\n\n')}
|
|
351
|
-
|
|
352
|
-
❓ Use \`force: true\` to push anyway, but this may cause runtime errors.
|
|
353
|
-
`;
|
|
354
|
-
return {
|
|
355
|
-
success: false,
|
|
356
|
-
result: { validationResults },
|
|
357
|
-
message
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
const success = await this.syncManager.pushArtifact(args.sys_id);
|
|
362
|
-
if (success) {
|
|
363
|
-
return {
|
|
364
|
-
success: true,
|
|
365
|
-
result: { pushed: true },
|
|
366
|
-
message: `✅ Artifact successfully pushed to ServiceNow! Changes are now live.`
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
return this.error('Failed to push artifact - check logs for details');
|
|
371
|
-
}
|
|
266
|
+
const success = await this.syncManager.pushArtifact(sys_id);
|
|
267
|
+
return {
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: 'text',
|
|
271
|
+
text: success
|
|
272
|
+
? `✅ Successfully pushed changes back to ServiceNow!`
|
|
273
|
+
: `❌ Failed to push changes. Check logs for details.`
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
};
|
|
372
277
|
}
|
|
373
278
|
catch (error) {
|
|
374
|
-
|
|
279
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
280
|
+
return {
|
|
281
|
+
content: [
|
|
282
|
+
{
|
|
283
|
+
type: 'text',
|
|
284
|
+
text: `❌ Failed to push artifact: ${errorMessage}`
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
};
|
|
375
288
|
}
|
|
376
289
|
}
|
|
377
|
-
/**
|
|
378
|
-
* Get sync status
|
|
379
|
-
*/
|
|
380
290
|
async getSyncStatus(args) {
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
383
|
-
const status = this.syncManager.getSyncStatus(
|
|
291
|
+
const { sys_id } = args;
|
|
292
|
+
if (sys_id) {
|
|
293
|
+
const status = this.syncManager.getSyncStatus(sys_id);
|
|
384
294
|
return {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: 'text',
|
|
298
|
+
text: `Sync status for ${sys_id}: ${status}`
|
|
299
|
+
}
|
|
300
|
+
]
|
|
388
301
|
};
|
|
389
302
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
**${a.name}** (${a.type})
|
|
396
|
-
- sys_id: \`${a.sys_id}\`
|
|
397
|
-
- Status: **${a.syncStatus}**
|
|
398
|
-
- Path: \`${a.localPath}\`
|
|
399
|
-
- Files: ${a.files.length}
|
|
400
|
-
- Modified: ${a.files.filter(f => f.isModified).length}
|
|
401
|
-
- Last sync: ${a.lastSyncedAt.toLocaleString()}
|
|
402
|
-
`).join('\n---\n')}
|
|
403
|
-
|
|
404
|
-
💡 Use \`snow_push_artifact <sys_id>\` to push changes
|
|
405
|
-
🧹 Use \`snow_sync_cleanup <sys_id>\` to remove local files
|
|
406
|
-
`;
|
|
407
|
-
return {
|
|
408
|
-
success: true,
|
|
409
|
-
result: artifacts,
|
|
410
|
-
message
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Cleanup local files
|
|
415
|
-
*/
|
|
416
|
-
async cleanup(args) {
|
|
417
|
-
try {
|
|
418
|
-
await this.syncManager.cleanup(args.sys_id, args.force);
|
|
303
|
+
else {
|
|
304
|
+
const artifacts = this.syncManager.listLocalArtifacts();
|
|
305
|
+
const statusText = artifacts.length > 0
|
|
306
|
+
? artifacts.map(a => `${a.name} (${a.sys_id}): ${a.syncStatus}`).join('\n')
|
|
307
|
+
: 'No local artifacts found';
|
|
419
308
|
return {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
309
|
+
content: [
|
|
310
|
+
{
|
|
311
|
+
type: 'text',
|
|
312
|
+
text: `Local artifacts status:\n${statusText}`
|
|
313
|
+
}
|
|
314
|
+
]
|
|
423
315
|
};
|
|
424
316
|
}
|
|
425
|
-
catch (error) {
|
|
426
|
-
return this.error(`Cleanup failed: ${error.message}`);
|
|
427
|
-
}
|
|
428
317
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
async listSupportedArtifacts() {
|
|
433
|
-
const types = (0, artifact_registry_1.getSupportedTables)();
|
|
434
|
-
const details = types.map(table => {
|
|
435
|
-
const config = artifact_registry_1.ARTIFACT_REGISTRY[table];
|
|
318
|
+
async listSupportedArtifacts(args) {
|
|
319
|
+
const supportedTypes = (0, artifact_registry_js_1.getSupportedTables)().map(table => {
|
|
320
|
+
const config = artifact_registry_js_1.ARTIFACT_REGISTRY[table];
|
|
436
321
|
return {
|
|
437
322
|
table,
|
|
438
|
-
displayName: config
|
|
439
|
-
folderName: config
|
|
440
|
-
fields: config
|
|
441
|
-
hasCoherence: (config
|
|
442
|
-
requiresES5: config
|
|
323
|
+
displayName: config?.displayName || table,
|
|
324
|
+
folderName: config?.folderName || table,
|
|
325
|
+
fields: config?.fieldMappings.length || 0,
|
|
326
|
+
hasCoherence: (config?.coherenceRules?.length || 0) > 0,
|
|
327
|
+
requiresES5: config?.fieldMappings.some(fm => fm.validateES5) || false
|
|
443
328
|
};
|
|
444
329
|
});
|
|
445
|
-
const message = `
|
|
446
|
-
📚 **Supported ServiceNow Artifact Types**
|
|
447
|
-
|
|
448
|
-
${details.map(d => `
|
|
449
|
-
**${d.displayName}**
|
|
450
|
-
- Table: \`${d.table}\`
|
|
451
|
-
- Folder: \`${d.folderName}/\`
|
|
452
|
-
- Fields: ${d.fields}
|
|
453
|
-
- Coherence Rules: ${d.hasCoherence ? '✅' : '❌'}
|
|
454
|
-
- ES5 Required: ${d.requiresES5 ? '⚠️ Yes' : '✅ No'}
|
|
455
|
-
`).join('\n')}
|
|
456
|
-
|
|
457
|
-
💡 **Usage:**
|
|
458
|
-
\`\`\`
|
|
459
|
-
snow_pull_artifact({ sys_id: 'abc123' }) // Auto-detect type
|
|
460
|
-
snow_pull_artifact({ sys_id: 'abc123', table: 'sp_widget' }) // Specific type
|
|
461
|
-
\`\`\`
|
|
462
|
-
`;
|
|
463
330
|
return {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
331
|
+
content: [
|
|
332
|
+
{
|
|
333
|
+
type: 'text',
|
|
334
|
+
text: `Supported ServiceNow artifact types for local sync:\n\n${supportedTypes.map(t => `📦 ${t.displayName} (${t.table})\n └── ${t.fields} fields, ES5: ${t.requiresES5 ? '✅' : '❌'}, Coherence: ${t.hasCoherence ? '✅' : '❌'}`).join('\n\n')}\n\nTotal: ${supportedTypes.length} artifact types supported`
|
|
335
|
+
}
|
|
336
|
+
]
|
|
467
337
|
};
|
|
468
338
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
*/
|
|
472
|
-
async validateCoherence(args) {
|
|
339
|
+
async validateArtifactCoherence(args) {
|
|
340
|
+
const { sys_id } = args;
|
|
473
341
|
try {
|
|
474
|
-
const results = await this.syncManager.validateArtifactCoherence(
|
|
475
|
-
|
|
476
|
-
return {
|
|
477
|
-
success: true,
|
|
478
|
-
result: { valid: true },
|
|
479
|
-
message: '✅ No coherence rules defined for this artifact type'
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
const allValid = results.every(r => r.valid);
|
|
483
|
-
const message = `
|
|
484
|
-
${allValid ? '✅' : '❌'} **Coherence Validation Results**
|
|
485
|
-
|
|
486
|
-
${results.map(r => {
|
|
487
|
-
let output = r.valid ? '✅ Valid\n' : '❌ Invalid\n';
|
|
488
|
-
if (r.errors.length > 0) {
|
|
489
|
-
output += '\n**Errors:**\n' + r.errors.map(e => `- ${e}`).join('\n');
|
|
490
|
-
}
|
|
491
|
-
if (r.warnings.length > 0) {
|
|
492
|
-
output += '\n**Warnings:**\n' + r.warnings.map(w => `- ${w}`).join('\n');
|
|
493
|
-
}
|
|
494
|
-
if (r.hints.length > 0) {
|
|
495
|
-
output += '\n**Hints:**\n' + r.hints.map(h => `- ${h}`).join('\n');
|
|
496
|
-
}
|
|
497
|
-
return output;
|
|
498
|
-
}).join('\n\n')}
|
|
499
|
-
`;
|
|
342
|
+
const results = await this.syncManager.validateArtifactCoherence(sys_id);
|
|
343
|
+
const hasErrors = results.some(r => !r.valid);
|
|
500
344
|
return {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
345
|
+
content: [
|
|
346
|
+
{
|
|
347
|
+
type: 'text',
|
|
348
|
+
text: hasErrors
|
|
349
|
+
? `⚠️ Coherence validation found issues:\n${results.filter(r => !r.valid).map(r => r.errors.join(', ')).join('\n')}`
|
|
350
|
+
: `✅ Artifact coherence validation passed!`
|
|
351
|
+
}
|
|
352
|
+
]
|
|
504
353
|
};
|
|
505
354
|
}
|
|
506
355
|
catch (error) {
|
|
507
|
-
|
|
356
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
357
|
+
return {
|
|
358
|
+
content: [
|
|
359
|
+
{
|
|
360
|
+
type: 'text',
|
|
361
|
+
text: `❌ Failed to validate coherence: ${errorMessage}`
|
|
362
|
+
}
|
|
363
|
+
]
|
|
364
|
+
};
|
|
508
365
|
}
|
|
509
366
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
367
|
+
async syncCleanup(args) {
|
|
368
|
+
const { sys_id, force = false } = args;
|
|
369
|
+
try {
|
|
370
|
+
await this.syncManager.cleanup(sys_id, force);
|
|
371
|
+
return {
|
|
372
|
+
content: [
|
|
373
|
+
{
|
|
374
|
+
type: 'text',
|
|
375
|
+
text: `✅ Successfully cleaned up local files for ${sys_id}`
|
|
376
|
+
}
|
|
377
|
+
]
|
|
378
|
+
};
|
|
517
379
|
}
|
|
518
|
-
|
|
519
|
-
|
|
380
|
+
catch (error) {
|
|
381
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
382
|
+
return {
|
|
383
|
+
content: [
|
|
384
|
+
{
|
|
385
|
+
type: 'text',
|
|
386
|
+
text: `❌ Failed to cleanup: ${errorMessage}`
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
};
|
|
520
390
|
}
|
|
521
|
-
|
|
391
|
+
}
|
|
392
|
+
async convertToES5(args) {
|
|
393
|
+
const { code, context = 'server_script' } = args;
|
|
394
|
+
// Basic ES5 conversion - in a real implementation this would be more sophisticated
|
|
522
395
|
let es5Code = code
|
|
523
|
-
|
|
524
|
-
.replace(/\
|
|
525
|
-
// Arrow functions
|
|
396
|
+
.replace(/\bconst\s+/g, 'var ')
|
|
397
|
+
.replace(/\blet\s+/g, 'var ')
|
|
526
398
|
.replace(/(\w+)\s*=>\s*{/g, 'function($1) {')
|
|
527
|
-
.replace(/(\
|
|
528
|
-
.replace(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
.replace(/`([^`]*)`/g, "'$1'")
|
|
532
|
-
// For...of → for loop
|
|
533
|
-
.replace(/for\s*\(\s*(?:const|let|var)\s+(\w+)\s+of\s+(\w+)\s*\)/g, 'for (var _i = 0; _i < $2.length; _i++) { var $1 = $2[_i];');
|
|
534
|
-
const message = `
|
|
535
|
-
✅ **Code converted to ES5**
|
|
536
|
-
|
|
537
|
-
⚠️ **Review the conversion carefully!**
|
|
538
|
-
This is a basic conversion. Complex features may need manual adjustment:
|
|
539
|
-
- Classes → function constructors
|
|
540
|
-
- async/await → callbacks
|
|
541
|
-
- Destructuring → individual assignments
|
|
542
|
-
- Spread operator → manual copying
|
|
543
|
-
|
|
544
|
-
**Common issues to check:**
|
|
545
|
-
- Arrow function this binding
|
|
546
|
-
- Default parameters
|
|
547
|
-
- Object method shorthand
|
|
548
|
-
`;
|
|
399
|
+
.replace(/(\w+)\s*=>\s*([^{])/g, 'function($1) { return $2; }')
|
|
400
|
+
.replace(/`([^`]*)`/g, (match, content) => {
|
|
401
|
+
return '"' + content.replace(/\$\{([^}]+)\}/g, '" + $1 + "') + '"';
|
|
402
|
+
});
|
|
549
403
|
return {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
404
|
+
content: [
|
|
405
|
+
{
|
|
406
|
+
type: 'text',
|
|
407
|
+
text: `✅ Converted to ES5 (basic conversion):\n\n\`\`\`javascript\n${es5Code}\n\`\`\`\n\n⚠️ Note: This is a basic conversion. Please review and test the code.`
|
|
408
|
+
}
|
|
409
|
+
]
|
|
553
410
|
};
|
|
554
411
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// Similar to Claude Code's search but for ServiceNow widgets
|
|
562
|
-
return {
|
|
563
|
-
success: true,
|
|
564
|
-
result: {},
|
|
565
|
-
message: `Search results for "${search_term}" in widgets`
|
|
566
|
-
};
|
|
412
|
+
// Legacy compatibility methods
|
|
413
|
+
async pullWidget(args) {
|
|
414
|
+
return this.pullArtifact({ ...args, table: 'sp_widget' });
|
|
415
|
+
}
|
|
416
|
+
async pushWidget(args) {
|
|
417
|
+
return this.pushArtifact(args);
|
|
567
418
|
}
|
|
568
419
|
}
|
|
569
|
-
|
|
420
|
+
// Start the server
|
|
421
|
+
async function main() {
|
|
422
|
+
const server = new ServiceNowLocalDevelopmentMCP();
|
|
423
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
424
|
+
await server.server.connect(transport);
|
|
425
|
+
console.error('🚀 ServiceNow Local Development MCP Server started');
|
|
426
|
+
}
|
|
427
|
+
if (require.main === module) {
|
|
428
|
+
main().catch((error) => {
|
|
429
|
+
console.error('❌ Server failed to start:', error);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
570
433
|
//# sourceMappingURL=servicenow-local-development-mcp.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.5",
|
|
4
4
|
"description": "ServiceNow development framework with MCP server integration. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides 18 MCP servers including local development sync for editing ServiceNow artifacts with Claude Code native tools, widget deployment with coherence validation, table operations, script execution, machine learning, advanced features, and comprehensive platform management.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|