snow-flow 3.5.10 → 3.5.12

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.
@@ -190,44 +190,56 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
190
190
  }));
191
191
  this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
192
192
  const { name, arguments: args } = request.params;
193
+ // Add timeout protection for MCP tool execution
194
+ const TOOL_TIMEOUT = 10000; // 10 seconds max per tool call
193
195
  try {
194
196
  this.logger.info(`šŸ”§ Executing tool: ${name}`, args);
195
- let result;
196
- switch (name) {
197
- case 'snow_pull_artifact':
198
- result = await this.pullArtifact(args);
199
- break;
200
- case 'snow_push_artifact':
201
- result = await this.pushArtifact(args);
202
- break;
203
- case 'snow_validate_artifact_coherence':
204
- result = await this.validateArtifactCoherence(args);
205
- break;
206
- case 'snow_sync_status':
207
- result = await this.getSyncStatus(args);
208
- break;
209
- case 'snow_list_supported_artifacts':
210
- result = await this.listSupportedArtifacts(args);
211
- break;
212
- case 'snow_sync_cleanup':
213
- result = await this.syncCleanup(args);
214
- break;
215
- case 'snow_convert_to_es5':
216
- result = await this.convertToES5(args);
217
- break;
218
- case 'snow_debug_widget_fetch':
219
- result = await this.debugWidgetFetch(args);
220
- break;
221
- // Legacy compatibility
222
- case 'snow_pull_widget':
223
- result = await this.pullWidget(args);
224
- break;
225
- case 'snow_push_widget':
226
- result = await this.pushWidget(args);
227
- break;
228
- default:
229
- throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
230
- }
197
+ // Create timeout promise
198
+ const timeoutPromise = new Promise((_, reject) => {
199
+ setTimeout(() => reject(new Error(`Tool ${name} timed out after ${TOOL_TIMEOUT / 1000}s`)), TOOL_TIMEOUT);
200
+ });
201
+ // Execute tool with timeout protection
202
+ const toolPromise = (async () => {
203
+ let result;
204
+ switch (name) {
205
+ case 'snow_pull_artifact':
206
+ result = await this.pullArtifact(args);
207
+ break;
208
+ case 'snow_push_artifact':
209
+ result = await this.pushArtifact(args);
210
+ break;
211
+ case 'snow_validate_artifact_coherence':
212
+ result = await this.validateArtifactCoherence(args);
213
+ break;
214
+ case 'snow_sync_status':
215
+ result = await this.getSyncStatus(args);
216
+ break;
217
+ case 'snow_list_supported_artifacts':
218
+ result = await this.listSupportedArtifacts(args);
219
+ break;
220
+ case 'snow_sync_cleanup':
221
+ result = await this.syncCleanup(args);
222
+ break;
223
+ case 'snow_convert_to_es5':
224
+ result = await this.convertToES5(args);
225
+ break;
226
+ case 'snow_debug_widget_fetch':
227
+ result = await this.debugWidgetFetch(args);
228
+ break;
229
+ // Legacy compatibility
230
+ case 'snow_pull_widget':
231
+ result = await this.pullWidget(args);
232
+ break;
233
+ case 'snow_push_widget':
234
+ result = await this.pushWidget(args);
235
+ break;
236
+ default:
237
+ throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
238
+ }
239
+ return result;
240
+ })();
241
+ // Race between tool execution and timeout
242
+ const result = await Promise.race([toolPromise, timeoutPromise]);
231
243
  this.logger.info(`āœ… Tool ${name} completed successfully`);
232
244
  return {
233
245
  content: result.content
@@ -249,16 +261,25 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
249
261
  }
250
262
  async pullArtifact(args) {
251
263
  const { sys_id, table } = args;
264
+ // Add timeout for pull operations
265
+ const PULL_TIMEOUT = 15000; // 15 seconds for pull operations
252
266
  try {
253
- let artifact;
254
- if (table) {
255
- // Use specified table
256
- artifact = await this.syncManager.pullArtifact(table, sys_id);
257
- }
258
- else {
259
- // Auto-detect table
260
- artifact = await this.syncManager.pullArtifactBySysId(sys_id);
261
- }
267
+ const pullPromise = (async () => {
268
+ let artifact;
269
+ if (table) {
270
+ // Use specified table
271
+ artifact = await this.syncManager.pullArtifact(table, sys_id);
272
+ }
273
+ else {
274
+ // Auto-detect table
275
+ artifact = await this.syncManager.pullArtifactBySysId(sys_id);
276
+ }
277
+ return artifact;
278
+ })();
279
+ const timeoutPromise = new Promise((_, reject) => {
280
+ setTimeout(() => reject(new Error(`Pull operation timed out after ${PULL_TIMEOUT / 1000}s`)), PULL_TIMEOUT);
281
+ });
282
+ const artifact = await Promise.race([pullPromise, timeoutPromise]);
262
283
  return {
263
284
  content: [
264
285
  {
@@ -431,8 +452,14 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
431
452
  }
432
453
  async debugWidgetFetch(args) {
433
454
  const { sys_id } = args;
455
+ // Debug operations get extra time
456
+ const DEBUG_TIMEOUT = 20000; // 20 seconds for debug operations
434
457
  try {
435
- const debugResults = await this.syncManager['smartFetcher'].debugFetchWidget(sys_id);
458
+ const debugPromise = this.syncManager['smartFetcher'].debugFetchWidget(sys_id);
459
+ const timeoutPromise = new Promise((_, reject) => {
460
+ setTimeout(() => reject(new Error(`Debug operation timed out after ${DEBUG_TIMEOUT / 1000}s`)), DEBUG_TIMEOUT);
461
+ });
462
+ const debugResults = await Promise.race([debugPromise, timeoutPromise]);
436
463
  let summaryText = `šŸ” Debug Results for Widget ${sys_id}\n\n`;
437
464
  // Check which methods worked
438
465
  const methods = ['searchRecords', 'getRecord', 'searchRecordsWithFields'];
@@ -490,13 +517,25 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
490
517
  }
491
518
  }
492
519
  exports.ServiceNowLocalDevelopmentMCP = ServiceNowLocalDevelopmentMCP;
493
- // Start the server
520
+ // Start the server with timeout protection
494
521
  async function main() {
495
- const mcpServer = new ServiceNowLocalDevelopmentMCP();
496
- const transport = new stdio_js_1.StdioServerTransport();
497
- // Access server through a public method
498
- await mcpServer.server.connect(transport);
499
- console.error('šŸš€ ServiceNow Local Development MCP Server started');
522
+ try {
523
+ const mcpServer = new ServiceNowLocalDevelopmentMCP();
524
+ const transport = new stdio_js_1.StdioServerTransport();
525
+ // Add timeout for server initialization
526
+ const INIT_TIMEOUT = 5000; // 5 seconds to start
527
+ const connectPromise = mcpServer.server.connect(transport);
528
+ const timeoutPromise = new Promise((_, reject) => {
529
+ setTimeout(() => reject(new Error('Server initialization timeout')), INIT_TIMEOUT);
530
+ });
531
+ await Promise.race([connectPromise, timeoutPromise]);
532
+ console.error('šŸš€ ServiceNow Local Development MCP Server started');
533
+ }
534
+ catch (error) {
535
+ console.error('āŒ Server failed to start within timeout:', error);
536
+ // Still allow server to run even if initial connection takes time
537
+ console.error('ā³ Server may still be initializing...');
538
+ }
500
539
  }
501
540
  if (require.main === module) {
502
541
  main().catch((error) => {
@@ -46,6 +46,7 @@ exports.ArtifactLocalSync = void 0;
46
46
  const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
48
  const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
49
+ const mcp_timeout_config_js_1 = require("./mcp-timeout-config.js");
49
50
  const artifact_registry_1 = require("./artifact-sync/artifact-registry");
50
51
  class ArtifactLocalSync {
51
52
  constructor(client, customBaseDir) {
@@ -126,22 +127,34 @@ class ArtifactLocalSync {
126
127
  throw new Error(`Unsupported artifact type: ${tableName}. Supported types: ${Object.keys(artifact_registry_1.ARTIFACT_REGISTRY).join(', ')}`);
127
128
  }
128
129
  console.log(`\nšŸ”„ Pulling ${config.displayName} (${sys_id}) to local files...`);
130
+ // Get timeout configuration
131
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
129
132
  // Use smart fetcher for known types, otherwise direct query
130
133
  let artifactData;
131
- if (tableName === 'sp_widget') {
132
- artifactData = await this.smartFetcher.fetchWidget(sys_id);
133
- }
134
- else if (tableName === 'sys_hub_flow') {
135
- artifactData = await this.smartFetcher.fetchFlow(sys_id);
136
- }
137
- else if (tableName === 'sys_script') {
138
- artifactData = await this.smartFetcher.fetchBusinessRule(sys_id);
134
+ // Fetch with timeout protection
135
+ try {
136
+ if (tableName === 'sp_widget') {
137
+ artifactData = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.smartFetcher.fetchWidget(sys_id), timeoutConfig.pullToolTimeout, `Fetch widget ${sys_id}`);
138
+ }
139
+ else if (tableName === 'sys_hub_flow') {
140
+ artifactData = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.smartFetcher.fetchFlow(sys_id), timeoutConfig.pullToolTimeout, `Fetch flow ${sys_id}`);
141
+ }
142
+ else if (tableName === 'sys_script') {
143
+ artifactData = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.smartFetcher.fetchBusinessRule(sys_id), timeoutConfig.pullToolTimeout, `Fetch business rule ${sys_id}`);
144
+ }
145
+ else {
146
+ // Generic fetch for other types
147
+ const allFields = config.fieldMappings.map(fm => fm.serviceNowField);
148
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(tableName, `sys_id=${sys_id}`, 1), timeoutConfig.queryToolTimeout, `Query ${tableName} ${sys_id}`);
149
+ artifactData = response.result?.[0];
150
+ }
139
151
  }
140
- else {
141
- // Generic fetch for other types
142
- const allFields = config.fieldMappings.map(fm => fm.serviceNowField);
143
- const response = await this.client.searchRecords(tableName, `sys_id=${sys_id}`, 1);
144
- artifactData = response.result?.[0];
152
+ catch (error) {
153
+ if (error instanceof Error && error.message.includes('timed out')) {
154
+ console.error(`ā±ļø Fetch timed out - ServiceNow may be slow or artifact is very large`);
155
+ console.error(`šŸ’” Try using snow_debug_widget_fetch to diagnose the issue`);
156
+ }
157
+ throw error;
145
158
  }
146
159
  if (!artifactData) {
147
160
  throw new Error(`Artifact not found: ${tableName}/${sys_id}`);
@@ -301,10 +314,11 @@ class ArtifactLocalSync {
301
314
  console.log(`\nā“ Continue with deployment anyway? (Issues might cause runtime errors)`);
302
315
  // In real implementation, prompt for confirmation
303
316
  }
304
- // Update in ServiceNow
317
+ // Update in ServiceNow with timeout protection
305
318
  try {
306
319
  console.log(`\nšŸ“¤ Updating ${config.displayName} in ServiceNow...`);
307
- await this.client.updateRecord(config.tableName, sys_id, updates);
320
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
321
+ await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.updateRecord(config.tableName, sys_id, updates), timeoutConfig.pushToolTimeout, `Update ${config.displayName} ${sys_id}`);
308
322
  artifact.syncStatus = 'synced';
309
323
  artifact.lastSyncedAt = new Date();
310
324
  console.log(`āœ… ${config.displayName} successfully updated in ServiceNow!`);
@@ -575,9 +589,12 @@ snow-flow sync status ${widget.sys_id}
575
589
  async pullArtifactBySysId(sys_id) {
576
590
  // Try to detect table by querying common tables
577
591
  const tables = Object.keys(artifact_registry_1.ARTIFACT_REGISTRY);
592
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
578
593
  for (const table of tables) {
579
594
  try {
580
- const response = await this.client.searchRecords(table, `sys_id=${sys_id}`, 1);
595
+ // Quick query with short timeout
596
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(table, `sys_id=${sys_id}`, 1), 3000, // 3 second timeout for detection
597
+ `Detect table for ${sys_id}`);
581
598
  if (response.result?.[0]) {
582
599
  console.log(`šŸŽ† Found artifact in table: ${table}`);
583
600
  return this.pullArtifact(table, sys_id);
@@ -0,0 +1,39 @@
1
+ /**
2
+ * MCP Server Timeout Configuration
3
+ *
4
+ * Provides fast, reliable timeout settings for MCP server operations
5
+ * to prevent Claude from timing out during API calls.
6
+ */
7
+ export interface MCPTimeoutConfig {
8
+ serverInitTimeout: number;
9
+ defaultToolTimeout: number;
10
+ queryToolTimeout: number;
11
+ pullToolTimeout: number;
12
+ pushToolTimeout: number;
13
+ debugToolTimeout: number;
14
+ scriptToolTimeout: number;
15
+ apiCallTimeout: number;
16
+ apiRetryDelay: number;
17
+ apiMaxRetries: number;
18
+ healthCheckInterval: number;
19
+ healthCheckTimeout: number;
20
+ maxResponseSize: number;
21
+ chunkDelay: number;
22
+ }
23
+ /**
24
+ * Get MCP timeout configuration based on environment
25
+ */
26
+ export declare function getMCPTimeoutConfig(): MCPTimeoutConfig;
27
+ /**
28
+ * Wrap a promise with timeout protection
29
+ */
30
+ export declare function withMCPTimeout<T>(promise: Promise<T>, timeoutMs: number, operationName?: string): Promise<T>;
31
+ /**
32
+ * Execute with retry logic and timeout
33
+ */
34
+ export declare function withMCPRetry<T>(fn: () => Promise<T>, config?: Partial<MCPTimeoutConfig>, operationName?: string): Promise<T>;
35
+ /**
36
+ * Quick health check with timeout
37
+ */
38
+ export declare function quickHealthCheck(checkFn: () => Promise<boolean>, timeoutMs?: number): Promise<boolean>;
39
+ //# sourceMappingURL=mcp-timeout-config.d.ts.map
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Server Timeout Configuration
4
+ *
5
+ * Provides fast, reliable timeout settings for MCP server operations
6
+ * to prevent Claude from timing out during API calls.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getMCPTimeoutConfig = getMCPTimeoutConfig;
10
+ exports.withMCPTimeout = withMCPTimeout;
11
+ exports.withMCPRetry = withMCPRetry;
12
+ exports.quickHealthCheck = quickHealthCheck;
13
+ /**
14
+ * Get MCP timeout configuration based on environment
15
+ */
16
+ function getMCPTimeoutConfig() {
17
+ const isDebug = process.env.DEBUG === 'true';
18
+ const isProduction = process.env.NODE_ENV === 'production';
19
+ // Balanced timeouts - long enough for real work, short enough to prevent hanging
20
+ const config = {
21
+ // Server should start reasonably quickly
22
+ serverInitTimeout: parseInt(process.env.MCP_SERVER_INIT_TIMEOUT || '10000'), // 10s for server init
23
+ // Tool timeouts - balanced for real operations
24
+ defaultToolTimeout: parseInt(process.env.MCP_DEFAULT_TOOL_TIMEOUT || '30000'), // 30s default
25
+ queryToolTimeout: parseInt(process.env.MCP_QUERY_TIMEOUT || '15000'), // 15s for queries
26
+ pullToolTimeout: parseInt(process.env.MCP_PULL_TIMEOUT || '60000'), // 60s for pulls (large widgets)
27
+ pushToolTimeout: parseInt(process.env.MCP_PUSH_TIMEOUT || '45000'), // 45s for pushes
28
+ debugToolTimeout: parseInt(process.env.MCP_DEBUG_TIMEOUT || '30000'), // 30s for debug
29
+ scriptToolTimeout: parseInt(process.env.MCP_SCRIPT_TIMEOUT || '120000'), // 2 min for scripts
30
+ // API calls get reasonable time
31
+ apiCallTimeout: parseInt(process.env.MCP_API_TIMEOUT || '15000'), // 15s per API call
32
+ apiRetryDelay: parseInt(process.env.MCP_API_RETRY_DELAY || '2000'), // 2s between retries
33
+ apiMaxRetries: parseInt(process.env.MCP_API_MAX_RETRIES || '3'), // 3 retries for resilience
34
+ // Health checks
35
+ healthCheckInterval: parseInt(process.env.MCP_HEALTH_INTERVAL || '30000'), // Every 30s
36
+ healthCheckTimeout: parseInt(process.env.MCP_HEALTH_TIMEOUT || '2000'), // 2s timeout
37
+ // Response optimization
38
+ maxResponseSize: parseInt(process.env.MCP_MAX_RESPONSE_SIZE || '100000'), // 100KB chunks
39
+ chunkDelay: parseInt(process.env.MCP_CHUNK_DELAY || '100'), // 100ms between chunks
40
+ };
41
+ // In debug mode, allow longer timeouts
42
+ if (isDebug) {
43
+ config.defaultToolTimeout *= 2;
44
+ config.queryToolTimeout *= 2;
45
+ config.pullToolTimeout *= 2;
46
+ config.pushToolTimeout *= 2;
47
+ config.debugToolTimeout *= 2;
48
+ config.scriptToolTimeout *= 2;
49
+ }
50
+ // In production, ensure fast responses
51
+ if (isProduction) {
52
+ config.apiMaxRetries = 1; // Only 1 retry in production
53
+ config.apiRetryDelay = 500; // Faster retry
54
+ }
55
+ return config;
56
+ }
57
+ /**
58
+ * Wrap a promise with timeout protection
59
+ */
60
+ async function withMCPTimeout(promise, timeoutMs, operationName = 'Operation') {
61
+ const timeoutPromise = new Promise((_, reject) => {
62
+ setTimeout(() => {
63
+ reject(new Error(`${operationName} timed out after ${timeoutMs / 1000}s`));
64
+ }, timeoutMs);
65
+ });
66
+ try {
67
+ return await Promise.race([promise, timeoutPromise]);
68
+ }
69
+ catch (error) {
70
+ if (error instanceof Error && error.message.includes('timed out')) {
71
+ // Log timeout for debugging
72
+ console.error(`ā±ļø MCP Timeout: ${operationName} exceeded ${timeoutMs}ms`);
73
+ // Add context about what to do
74
+ error.message += ' - Consider increasing timeout or optimizing the operation';
75
+ }
76
+ throw error;
77
+ }
78
+ }
79
+ /**
80
+ * Execute with retry logic and timeout
81
+ */
82
+ async function withMCPRetry(fn, config = {}, operationName = 'Operation') {
83
+ const fullConfig = { ...getMCPTimeoutConfig(), ...config };
84
+ let lastError = null;
85
+ for (let attempt = 0; attempt <= fullConfig.apiMaxRetries; attempt++) {
86
+ try {
87
+ // Try with timeout
88
+ const result = await withMCPTimeout(fn(), fullConfig.defaultToolTimeout, `${operationName} (attempt ${attempt + 1})`);
89
+ return result;
90
+ }
91
+ catch (error) {
92
+ lastError = error;
93
+ // Don't retry on non-retryable errors
94
+ if (error instanceof Error) {
95
+ if (error.message.includes('Authentication') ||
96
+ error.message.includes('Permission') ||
97
+ error.message.includes('Not found')) {
98
+ throw error; // Don't retry auth/permission errors
99
+ }
100
+ }
101
+ // If we have retries left, wait and try again
102
+ if (attempt < fullConfig.apiMaxRetries) {
103
+ console.log(`āš ļø ${operationName} failed, retrying in ${fullConfig.apiRetryDelay / 1000}s...`);
104
+ await new Promise(resolve => setTimeout(resolve, fullConfig.apiRetryDelay));
105
+ }
106
+ }
107
+ }
108
+ // All retries exhausted
109
+ throw lastError || new Error(`${operationName} failed after ${fullConfig.apiMaxRetries} retries`);
110
+ }
111
+ /**
112
+ * Quick health check with timeout
113
+ */
114
+ async function quickHealthCheck(checkFn, timeoutMs = 2000) {
115
+ try {
116
+ return await withMCPTimeout(checkFn(), timeoutMs, 'Health check');
117
+ }
118
+ catch (error) {
119
+ // Health check failed or timed out
120
+ return false;
121
+ }
122
+ }
123
+ //# sourceMappingURL=mcp-timeout-config.js.map
@@ -86,8 +86,6 @@ class ServiceNowClient {
86
86
  // šŸ”§ CRITICAL FIX: Add makeRequest method to Axios instance to fix phantom calls
87
87
  // Some code expects makeRequest to exist on this.client (the Axios instance)
88
88
  this.client.makeRequest = async (config) => {
89
- this.logger.debug('šŸ”§ AXIOS makeRequest called! Config:', config);
90
- this.logger.debug('šŸ”§ Routing to appropriate HTTP method...');
91
89
  // Route to the appropriate Axios method based on the request config
92
90
  const method = (config.method || 'GET').toLowerCase();
93
91
  const url = config.url || config.endpoint;
@@ -2888,17 +2886,13 @@ try {
2888
2886
  * This method provides compatibility for code that expects makeRequest
2889
2887
  */
2890
2888
  async makeRequest(config) {
2891
- this.logger.info('šŸ”§ MAKEQUEST CALLED! Stack trace:', new Error().stack);
2892
- this.logger.info('šŸ”§ TEMP FIX: makeRequest called with config:', config);
2893
- this.logger.info('šŸ”§ This instance constructor:', this.constructor.name);
2894
- this.logger.info('šŸ”§ This instance methods:', Object.getOwnPropertyNames(Object.getPrototypeOf(this)));
2889
+ // Debug logging removed - was causing noise in production
2895
2890
  try {
2896
2891
  await this.ensureAuthenticated();
2897
2892
  // Route the request to the appropriate HTTP method
2898
2893
  const method = (config.method || 'GET').toLowerCase();
2899
2894
  const url = config.url || config.endpoint;
2900
2895
  const data = config.data || config.body;
2901
- this.logger.info(`šŸ”§ Routing ${method.toUpperCase()} request to: ${url}`);
2902
2896
  switch (method) {
2903
2897
  case 'get':
2904
2898
  return await this.get(url, config.params);
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.SmartFieldFetcher = void 0;
10
10
  exports.createFetchStrategyHint = createFetchStrategyHint;
11
11
  const artifact_registry_js_1 = require("./artifact-sync/artifact-registry.js");
12
+ const mcp_timeout_config_js_1 = require("./mcp-timeout-config.js");
12
13
  // Widget field groups with relationship context - 20K per field for better context
13
14
  const WIDGET_FIELD_GROUPS = [
14
15
  {
@@ -160,9 +161,10 @@ class SmartFieldFetcher {
160
161
  };
161
162
  // Try to fetch all fields first, then fall back to individual fields if too large
162
163
  console.log(`šŸ“¦ Attempting to fetch complete widget data...`);
164
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
163
165
  try {
164
- // Try to get all fields at once
165
- const response = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
166
+ // Try to get all fields at once with timeout protection
167
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1), timeoutConfig.queryToolTimeout, `Fetch complete widget ${sys_id}`);
166
168
  if (response && response.success && response.data && response.data.result && response.data.result.length > 0) {
167
169
  const widgetData = response.data.result[0];
168
170
  console.log(`āœ… Successfully fetched complete widget`);
@@ -192,7 +194,7 @@ class SmartFieldFetcher {
192
194
  console.log(`šŸ”„ Switching to more robust fetching approach...`);
193
195
  // First, get the widget with minimal fields to ensure it exists
194
196
  try {
195
- const basicResponse = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
197
+ const basicResponse = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1), timeoutConfig.queryToolTimeout, `Basic widget fetch ${sys_id}`);
196
198
  if (!basicResponse || !basicResponse.success || !basicResponse.data || !basicResponse.data.result || basicResponse.data.result.length === 0) {
197
199
  throw new Error(`Widget with sys_id ${sys_id} not found`);
198
200
  }
@@ -227,8 +229,9 @@ class SmartFieldFetcher {
227
229
  // If critical fields are missing, try alternative approach
228
230
  if (!widgetData.script && !widgetData.client_script && !widgetData.template) {
229
231
  console.log(`āš ļø Critical fields missing, trying direct API call...`);
230
- // Try using getRecord instead of searchRecords
231
- const directResponse = await this.client.getRecord('sp_widget', sys_id);
232
+ // Try using getRecord instead of searchRecords with short timeout
233
+ const directResponse = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.getRecord('sp_widget', sys_id), 5000, // 5 second timeout for direct fetch
234
+ `Direct widget fetch ${sys_id}`);
232
235
  if (directResponse && directResponse.success && directResponse.data && directResponse.data.result) {
233
236
  const directData = directResponse.data.result;
234
237
  // Merge any new data we got
@@ -360,10 +363,11 @@ class SmartFieldFetcher {
360
363
  async debugFetchWidget(sys_id) {
361
364
  console.log(`\nšŸ” DEBUG: Testing different fetch approaches for widget ${sys_id}\n`);
362
365
  const results = {};
363
- // Test 1: Basic searchRecords
366
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
367
+ // Test 1: Basic searchRecords with timeout
364
368
  try {
365
- console.log(`Test 1: searchRecords...`);
366
- const test1 = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
369
+ console.log(`Test 1: searchRecords (${timeoutConfig.queryToolTimeout / 1000}s timeout)...`);
370
+ const test1 = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1), timeoutConfig.queryToolTimeout, 'searchRecords test');
367
371
  console.log(` - Response structure: success=${test1?.success}, has data=${!!test1?.data}, has result=${!!test1?.data?.result}`);
368
372
  if (test1?.data?.result?.[0]) {
369
373
  const widget = test1.data.result[0];
@@ -377,10 +381,10 @@ class SmartFieldFetcher {
377
381
  catch (e) {
378
382
  console.log(` āŒ Error: ${e.message}`);
379
383
  }
380
- // Test 2: getRecord
384
+ // Test 2: getRecord with timeout
381
385
  try {
382
- console.log(`Test 2: getRecord...`);
383
- const test2 = await this.client.getRecord('sp_widget', sys_id);
386
+ console.log(`Test 2: getRecord (${timeoutConfig.queryToolTimeout / 1000}s timeout)...`);
387
+ const test2 = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.getRecord('sp_widget', sys_id), timeoutConfig.queryToolTimeout, 'getRecord test');
384
388
  console.log(` - Response structure: success=${test2?.success}, has data=${!!test2?.data}, has result=${!!test2?.data?.result}`);
385
389
  if (test2?.data?.result) {
386
390
  const widget = test2.data.result;
@@ -394,10 +398,10 @@ class SmartFieldFetcher {
394
398
  catch (e) {
395
399
  console.log(` āŒ Error: ${e.message}`);
396
400
  }
397
- // Test 3: searchRecordsWithFields
401
+ // Test 3: searchRecordsWithFields with timeout
398
402
  try {
399
- console.log(`Test 3: searchRecordsWithFields with specific fields...`);
400
- const test3 = await this.client.searchRecordsWithFields('sp_widget', `sys_id=${sys_id}`, ['name', 'script', 'client_script', 'template', 'css'], 1);
403
+ console.log(`Test 3: searchRecordsWithFields (${timeoutConfig.queryToolTimeout / 1000}s timeout)...`);
404
+ const test3 = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecordsWithFields('sp_widget', `sys_id=${sys_id}`, ['name', 'script', 'client_script', 'template', 'css'], 1), timeoutConfig.queryToolTimeout, 'searchRecordsWithFields test');
401
405
  console.log(` - Response structure: success=${test3?.success}, has data=${!!test3?.data}, has result=${!!test3?.data?.result}`);
402
406
  if (test3?.data?.result?.[0]) {
403
407
  const widget = test3.data.result[0];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.5.10",
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.",
3
+ "version": "3.5.12",
4
+ "description": "ServiceNow development framework with MCP server integration and balanced timeout protection. Features intelligent timeout configuration for long operations while preventing Claude API timeouts. Debug logging cleaned up for production use. 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",
7
7
  "bin": {