snow-flow 3.5.5 ā 3.5.7
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-local-development-mcp.d.ts +16 -1
- package/dist/mcp/servicenow-local-development-mcp.js +8 -3
- package/dist/mcp/shared/enhanced-base-mcp-server.d.ts +3 -2
- package/dist/mcp/shared/enhanced-base-mcp-server.js +1 -1
- package/dist/utils/artifact-local-sync.d.ts +1 -1
- package/dist/utils/artifact-local-sync.js +6 -14
- package/dist/utils/servicenow-client-with-tracking.js +1 -1
- package/dist/utils/smart-field-fetcher.d.ts +1 -1
- package/dist/utils/smart-field-fetcher.js +13 -29
- package/package.json +1 -1
|
@@ -8,5 +8,20 @@
|
|
|
8
8
|
*
|
|
9
9
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
import { EnhancedBaseMCPServer } from './shared/enhanced-base-mcp-server.js';
|
|
12
|
+
export declare class ServiceNowLocalDevelopmentMCP extends EnhancedBaseMCPServer {
|
|
13
|
+
private syncManager;
|
|
14
|
+
constructor();
|
|
15
|
+
private setupSyncManager;
|
|
16
|
+
private setupHandlers;
|
|
17
|
+
private pullArtifact;
|
|
18
|
+
private pushArtifact;
|
|
19
|
+
private getSyncStatus;
|
|
20
|
+
private listSupportedArtifacts;
|
|
21
|
+
private validateArtifactCoherence;
|
|
22
|
+
private syncCleanup;
|
|
23
|
+
private convertToES5;
|
|
24
|
+
private pullWidget;
|
|
25
|
+
private pushWidget;
|
|
26
|
+
}
|
|
12
27
|
//# sourceMappingURL=servicenow-local-development-mcp.d.ts.map
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ServiceNowLocalDevelopmentMCP = void 0;
|
|
13
14
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
14
15
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
15
16
|
const enhanced_base_mcp_server_js_1 = require("./shared/enhanced-base-mcp-server.js");
|
|
@@ -211,7 +212,9 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
|
|
|
211
212
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
212
213
|
}
|
|
213
214
|
this.logger.info(`ā
Tool ${name} completed successfully`);
|
|
214
|
-
return
|
|
215
|
+
return {
|
|
216
|
+
content: result.content
|
|
217
|
+
};
|
|
215
218
|
}
|
|
216
219
|
catch (error) {
|
|
217
220
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -417,11 +420,13 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
|
|
|
417
420
|
return this.pushArtifact(args);
|
|
418
421
|
}
|
|
419
422
|
}
|
|
423
|
+
exports.ServiceNowLocalDevelopmentMCP = ServiceNowLocalDevelopmentMCP;
|
|
420
424
|
// Start the server
|
|
421
425
|
async function main() {
|
|
422
|
-
const
|
|
426
|
+
const mcpServer = new ServiceNowLocalDevelopmentMCP();
|
|
423
427
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
424
|
-
|
|
428
|
+
// Access server through a public method
|
|
429
|
+
await mcpServer.server.connect(transport);
|
|
425
430
|
console.error('š ServiceNow Local Development MCP Server started');
|
|
426
431
|
}
|
|
427
432
|
if (require.main === module) {
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
5
|
import { ServiceNowClientWithTracking } from '../../utils/servicenow-client-with-tracking.js';
|
|
6
6
|
import { MCPLogger } from './mcp-logger.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ServiceNowOAuth } from '../../utils/snow-oauth.js';
|
|
8
8
|
export interface MCPToolResult {
|
|
9
9
|
content: Array<{
|
|
10
10
|
type: string;
|
|
11
11
|
text: string;
|
|
12
12
|
}>;
|
|
13
|
+
[key: string]: unknown;
|
|
13
14
|
}
|
|
14
15
|
export declare abstract class EnhancedBaseMCPServer {
|
|
15
16
|
protected server: Server;
|
|
16
17
|
protected client: ServiceNowClientWithTracking;
|
|
17
18
|
protected logger: MCPLogger;
|
|
18
|
-
protected oauth:
|
|
19
|
+
protected oauth: ServiceNowOAuth;
|
|
19
20
|
protected isAuthenticated: boolean;
|
|
20
21
|
constructor(name: string, version?: string);
|
|
21
22
|
/**
|
|
@@ -19,7 +19,7 @@ class EnhancedBaseMCPServer {
|
|
|
19
19
|
// Create enhanced client with tracking
|
|
20
20
|
this.client = new servicenow_client_with_tracking_js_1.ServiceNowClientWithTracking(this.logger);
|
|
21
21
|
// Initialize OAuth
|
|
22
|
-
this.oauth = new snow_oauth_js_1.
|
|
22
|
+
this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
23
23
|
// Create server with capabilities
|
|
24
24
|
this.server = new index_js_1.Server({
|
|
25
25
|
name,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* THIS IS THE BRIDGE BETWEEN SERVICENOW AND CLAUDE CODE!
|
|
9
9
|
*/
|
|
10
|
-
import { ServiceNowClient } from './servicenow-client';
|
|
10
|
+
import { ServiceNowClient } from './servicenow-client.js';
|
|
11
11
|
import { ArtifactTypeConfig, FieldMapping, ValidationResult } from './artifact-sync/artifact-registry';
|
|
12
12
|
export interface LocalArtifact {
|
|
13
13
|
sys_id: string;
|
|
@@ -46,13 +46,13 @@ exports.ArtifactLocalSync = void 0;
|
|
|
46
46
|
const fs = __importStar(require("fs"));
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
48
|
const os = __importStar(require("os"));
|
|
49
|
-
const
|
|
49
|
+
const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
|
|
50
50
|
const artifact_registry_1 = require("./artifact-sync/artifact-registry");
|
|
51
51
|
class ArtifactLocalSync {
|
|
52
52
|
constructor(client) {
|
|
53
53
|
this.artifacts = new Map();
|
|
54
54
|
this.client = client;
|
|
55
|
-
this.smartFetcher = new
|
|
55
|
+
this.smartFetcher = new smart_field_fetcher_js_1.SmartFieldFetcher(client);
|
|
56
56
|
// Create base directory for Snow-Flow artifacts
|
|
57
57
|
this.baseDir = path.join(os.tmpdir(), 'snow-flow-artifacts');
|
|
58
58
|
if (!fs.existsSync(this.baseDir)) {
|
|
@@ -84,11 +84,7 @@ class ArtifactLocalSync {
|
|
|
84
84
|
else {
|
|
85
85
|
// Generic fetch for other types
|
|
86
86
|
const allFields = config.fieldMappings.map(fm => fm.serviceNowField);
|
|
87
|
-
const response = await this.client.
|
|
88
|
-
query: `sys_id=${sys_id}`,
|
|
89
|
-
fields: allFields.concat(['sys_id', 'sys_created_on', 'sys_updated_on']),
|
|
90
|
-
limit: 1
|
|
91
|
-
});
|
|
87
|
+
const response = await this.client.searchRecords(tableName, `sys_id=${sys_id}`, 1);
|
|
92
88
|
artifactData = response.result?.[0];
|
|
93
89
|
}
|
|
94
90
|
if (!artifactData) {
|
|
@@ -320,7 +316,7 @@ class ArtifactLocalSync {
|
|
|
320
316
|
// Update in ServiceNow
|
|
321
317
|
try {
|
|
322
318
|
console.log(`\nš¤ Updating ${config.displayName} in ServiceNow...`);
|
|
323
|
-
await this.client.
|
|
319
|
+
await this.client.updateRecord(config.tableName, sys_id, updates);
|
|
324
320
|
artifact.syncStatus = 'synced';
|
|
325
321
|
artifact.lastSyncedAt = new Date();
|
|
326
322
|
console.log(`ā
${config.displayName} successfully updated in ServiceNow!`);
|
|
@@ -382,7 +378,7 @@ class ArtifactLocalSync {
|
|
|
382
378
|
// Update in ServiceNow
|
|
383
379
|
try {
|
|
384
380
|
console.log(`\nš¤ Updating widget in ServiceNow...`);
|
|
385
|
-
await this.client.
|
|
381
|
+
await this.client.updateRecord('sp_widget', sys_id, updates);
|
|
386
382
|
artifact.syncStatus = 'synced';
|
|
387
383
|
artifact.lastSyncedAt = new Date();
|
|
388
384
|
console.log(`ā
Widget successfully updated in ServiceNow!`);
|
|
@@ -647,11 +643,7 @@ snow-flow sync status ${widget.sys_id}
|
|
|
647
643
|
const tables = Object.keys(artifact_registry_1.ARTIFACT_REGISTRY);
|
|
648
644
|
for (const table of tables) {
|
|
649
645
|
try {
|
|
650
|
-
const response = await this.client.
|
|
651
|
-
query: `sys_id=${sys_id}`,
|
|
652
|
-
fields: ['sys_id'],
|
|
653
|
-
limit: 1
|
|
654
|
-
});
|
|
646
|
+
const response = await this.client.searchRecords(table, `sys_id=${sys_id}`, 1);
|
|
655
647
|
if (response.result?.[0]) {
|
|
656
648
|
console.log(`š Found artifact in table: ${table}`);
|
|
657
649
|
return this.pullArtifact(table, sys_id);
|
|
@@ -106,7 +106,7 @@ class ServiceNowClientWithTracking extends servicenow_client_js_1.ServiceNowClie
|
|
|
106
106
|
async getRecord(table, sysId, fields) {
|
|
107
107
|
this.mcpLogger.progress(`Fetching ${table} record: ${sysId}`);
|
|
108
108
|
try {
|
|
109
|
-
const result = await super.getRecord(table, sysId
|
|
109
|
+
const result = await super.getRecord(table, sysId);
|
|
110
110
|
// Estimate tokens
|
|
111
111
|
if (result?.data?.result) {
|
|
112
112
|
const responseSize = JSON.stringify(result.data.result).length;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Intelligently fetches large artifacts by splitting fields into chunks
|
|
5
5
|
* while maintaining context relationships between fields.
|
|
6
6
|
*/
|
|
7
|
-
import { ServiceNowClient } from './servicenow-client';
|
|
7
|
+
import { ServiceNowClient } from './servicenow-client.js';
|
|
8
8
|
export interface FetchStrategy {
|
|
9
9
|
table: string;
|
|
10
10
|
sys_id: string;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.SmartFieldFetcher = void 0;
|
|
10
10
|
exports.createFetchStrategyHint = createFetchStrategyHint;
|
|
11
|
-
const
|
|
11
|
+
const artifact_registry_js_1 = require("./artifact-sync/artifact-registry.js");
|
|
12
12
|
// Widget field groups with relationship context - 20K per field for better context
|
|
13
13
|
const WIDGET_FIELD_GROUPS = [
|
|
14
14
|
{
|
|
@@ -112,7 +112,7 @@ class SmartFieldFetcher {
|
|
|
112
112
|
async fetchArtifact(table, sys_id) {
|
|
113
113
|
console.log(`\nš Smart fetching ${table}: ${sys_id}`);
|
|
114
114
|
const fieldGroups = this.getFieldGroups(table);
|
|
115
|
-
const config = (0,
|
|
115
|
+
const config = (0, artifact_registry_js_1.getArtifactConfig)(table);
|
|
116
116
|
const results = {
|
|
117
117
|
_fetch_strategy: 'smart_chunked',
|
|
118
118
|
_context_hint: config ? `${config.displayName} - fields fetched in groups to respect token limits` : 'Fields fetched separately but are related',
|
|
@@ -122,14 +122,10 @@ class SmartFieldFetcher {
|
|
|
122
122
|
for (const group of fieldGroups) {
|
|
123
123
|
console.log(`š¦ Fetching ${group.groupName}: ${group.description}`);
|
|
124
124
|
try {
|
|
125
|
-
const response = await this.client.
|
|
126
|
-
|
|
127
|
-
fields: group.fields,
|
|
128
|
-
limit: 1
|
|
129
|
-
});
|
|
130
|
-
if (response.result?.[0]) {
|
|
125
|
+
const response = await this.client.getRecord(table, sys_id);
|
|
126
|
+
if (response) {
|
|
131
127
|
results._field_groups[group.groupName] = {
|
|
132
|
-
data: response
|
|
128
|
+
data: response,
|
|
133
129
|
description: group.description,
|
|
134
130
|
fields: group.fields
|
|
135
131
|
};
|
|
@@ -167,14 +163,10 @@ class SmartFieldFetcher {
|
|
|
167
163
|
for (const group of WIDGET_FIELD_GROUPS) {
|
|
168
164
|
console.log(`š¦ Fetching ${group.groupName}: ${group.description}`);
|
|
169
165
|
try {
|
|
170
|
-
const response = await this.client.
|
|
171
|
-
|
|
172
|
-
fields: group.fields,
|
|
173
|
-
limit: 1
|
|
174
|
-
});
|
|
175
|
-
if (response.result?.[0]) {
|
|
166
|
+
const response = await this.client.getRecord('sp_widget', sys_id);
|
|
167
|
+
if (response) {
|
|
176
168
|
results._field_groups[group.groupName] = {
|
|
177
|
-
data: response
|
|
169
|
+
data: response,
|
|
178
170
|
description: group.description,
|
|
179
171
|
fields: group.fields
|
|
180
172
|
};
|
|
@@ -222,13 +214,9 @@ class SmartFieldFetcher {
|
|
|
222
214
|
for (const field of fields) {
|
|
223
215
|
try {
|
|
224
216
|
console.log(` š Fetching field: ${field}`);
|
|
225
|
-
const response = await this.client.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
limit: 1
|
|
229
|
-
});
|
|
230
|
-
if (response.result?.[0]) {
|
|
231
|
-
result.data[field] = response.result[0][field];
|
|
217
|
+
const response = await this.client.getRecord(table, sys_id);
|
|
218
|
+
if (response) {
|
|
219
|
+
result.data[field] = response[field];
|
|
232
220
|
result._field_status[field] = 'success';
|
|
233
221
|
}
|
|
234
222
|
}
|
|
@@ -284,11 +272,7 @@ class SmartFieldFetcher {
|
|
|
284
272
|
// Use CONTAINS operator for field search
|
|
285
273
|
const query = `${field}CONTAINS${searchTerm}${additionalQuery ? '^' + additionalQuery : ''}`;
|
|
286
274
|
try {
|
|
287
|
-
const response = await this.client.
|
|
288
|
-
query: query,
|
|
289
|
-
fields: ['sys_id', 'name', field.substring(0, 50)], // Get preview of field
|
|
290
|
-
limit: 10
|
|
291
|
-
});
|
|
275
|
+
const response = await this.client.searchRecords(table, query, 10);
|
|
292
276
|
console.log(` ā
Found ${response.result?.length || 0} matches`);
|
|
293
277
|
return response.result || [];
|
|
294
278
|
}
|
|
@@ -311,7 +295,7 @@ class SmartFieldFetcher {
|
|
|
311
295
|
return BUSINESS_RULE_FIELD_GROUPS;
|
|
312
296
|
}
|
|
313
297
|
// Try to get from artifact registry
|
|
314
|
-
const config = (0,
|
|
298
|
+
const config = (0, artifact_registry_js_1.getArtifactConfig)(table);
|
|
315
299
|
if (config) {
|
|
316
300
|
return this.createFieldGroupsFromRegistry(config);
|
|
317
301
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.7",
|
|
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",
|