snow-flow 1.3.17 → 1.3.19

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.
@@ -5231,10 +5231,145 @@ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual co
5231
5231
  return await this.deployFlow(scopedConfig);
5232
5232
  case 'application':
5233
5233
  return await this.deployApplication(scopedConfig);
5234
+ case 'xml_update_set':
5235
+ return await this.deployXMLUpdateSet(scopedConfig);
5234
5236
  default:
5235
5237
  throw new Error(`Unsupported artifact type for unified deployment: ${type}`);
5236
5238
  }
5237
5239
  }
5240
+ /**
5241
+ * Deploy XML Update Set to ServiceNow
5242
+ */
5243
+ async deployXMLUpdateSet(config) {
5244
+ const { xml_file_path, auto_preview = true, auto_commit = true } = config;
5245
+ if (!xml_file_path) {
5246
+ throw new Error('XML file path is required for xml_update_set deployment');
5247
+ }
5248
+ this.logger.info('🚀 Deploying XML Update Set', {
5249
+ file: xml_file_path,
5250
+ auto_preview,
5251
+ auto_commit
5252
+ });
5253
+ try {
5254
+ // Read XML file
5255
+ const fs = require('fs').promises;
5256
+ const xmlContent = await fs.readFile(xml_file_path, 'utf-8');
5257
+ // Import XML as remote update set
5258
+ const importResponse = await this.client.makeRequest({
5259
+ method: 'POST',
5260
+ url: '/api/now/table/sys_remote_update_set',
5261
+ headers: {
5262
+ 'Content-Type': 'application/xml',
5263
+ 'Accept': 'application/json'
5264
+ },
5265
+ data: xmlContent
5266
+ });
5267
+ if (!importResponse.result || !importResponse.result.sys_id) {
5268
+ throw new Error('Failed to import XML update set');
5269
+ }
5270
+ const remoteUpdateSetId = importResponse.result.sys_id;
5271
+ this.logger.info('✅ XML imported successfully', { sys_id: remoteUpdateSetId });
5272
+ // Load the update set
5273
+ await this.client.makeRequest({
5274
+ method: 'PUT',
5275
+ url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
5276
+ data: {
5277
+ state: 'loaded'
5278
+ }
5279
+ });
5280
+ // Find the loaded update set
5281
+ const loadedResponse = await this.client.makeRequest({
5282
+ method: 'GET',
5283
+ url: '/api/now/table/sys_update_set',
5284
+ params: {
5285
+ sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
5286
+ sysparm_limit: 1
5287
+ }
5288
+ });
5289
+ if (!loadedResponse.result || loadedResponse.result.length === 0) {
5290
+ throw new Error('Failed to find loaded update set');
5291
+ }
5292
+ const updateSetId = loadedResponse.result[0].sys_id;
5293
+ const updateSetName = loadedResponse.result[0].name;
5294
+ // Preview if requested
5295
+ if (auto_preview) {
5296
+ const previewResponse = await this.client.makeRequest({
5297
+ method: 'POST',
5298
+ url: `/api/now/table/sys_update_set/${updateSetId}/preview`
5299
+ });
5300
+ // Check preview results
5301
+ const previewProblems = await this.client.makeRequest({
5302
+ method: 'GET',
5303
+ url: '/api/now/table/sys_update_preview_problem',
5304
+ params: {
5305
+ sysparm_query: `update_set=${updateSetId}`,
5306
+ sysparm_limit: 100
5307
+ }
5308
+ });
5309
+ if (previewProblems.result && previewProblems.result.length > 0) {
5310
+ const problems = previewProblems.result.map((p) => `- ${p.type}: ${p.description}`).join('\n');
5311
+ if (auto_commit) {
5312
+ this.logger.warn('Preview found problems, skipping auto-commit', { problems });
5313
+ }
5314
+ return {
5315
+ success: true,
5316
+ message: 'XML imported and previewed with problems',
5317
+ update_set_id: updateSetId,
5318
+ update_set_name: updateSetName,
5319
+ preview_status: 'problems_found',
5320
+ problems: previewProblems.result,
5321
+ next_steps: [
5322
+ '1. Review preview problems in ServiceNow',
5323
+ '2. Resolve any issues',
5324
+ '3. Commit manually when ready'
5325
+ ]
5326
+ };
5327
+ }
5328
+ // Commit if clean and requested
5329
+ if (auto_commit) {
5330
+ await this.client.makeRequest({
5331
+ method: 'POST',
5332
+ url: `/api/now/table/sys_update_set/${updateSetId}/commit`
5333
+ });
5334
+ return {
5335
+ success: true,
5336
+ message: '✅ XML Update Set imported, previewed, and committed successfully!',
5337
+ update_set_id: updateSetId,
5338
+ update_set_name: updateSetName,
5339
+ status: 'committed',
5340
+ flow_location: 'Flow Designer > Designer',
5341
+ next_steps: [
5342
+ '1. Navigate to Flow Designer',
5343
+ '2. Your flow should be visible in the list',
5344
+ '3. Open the flow to verify all components'
5345
+ ]
5346
+ };
5347
+ }
5348
+ }
5349
+ // Return success without preview/commit
5350
+ return {
5351
+ success: true,
5352
+ message: 'XML Update Set imported successfully',
5353
+ update_set_id: updateSetId,
5354
+ update_set_name: updateSetName,
5355
+ status: 'imported',
5356
+ next_steps: [
5357
+ '1. Navigate to System Update Sets > Local Update Sets',
5358
+ '2. Find your update set: ' + updateSetName,
5359
+ '3. Click Preview Update Set',
5360
+ '4. Review and commit when ready'
5361
+ ]
5362
+ };
5363
+ }
5364
+ catch (error) {
5365
+ const errorMsg = error instanceof Error ? error.message : String(error);
5366
+ this.logger.error('XML deployment failed', { error: errorMsg, file: xml_file_path });
5367
+ if (errorMsg.includes('ENOENT') || errorMsg.includes('no such file')) {
5368
+ throw new Error(`XML file not found: ${xml_file_path}`);
5369
+ }
5370
+ throw new Error(`XML deployment failed: ${errorMsg}`);
5371
+ }
5372
+ }
5238
5373
  /**
5239
5374
  * Check if error is permission-related
5240
5375
  */
@@ -4,6 +4,39 @@
4
4
  * ServiceNow Flow Composer MCP Server
5
5
  * Natural language flow creation with multi-artifact orchestration
6
6
  */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
7
40
  Object.defineProperty(exports, "__esModule", { value: true });
8
41
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
9
42
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
@@ -11,7 +44,6 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
11
44
  const servicenow_client_js_1 = require("../utils/servicenow-client.js");
12
45
  const snow_oauth_js_1 = require("../utils/snow-oauth.js");
13
46
  const logger_js_1 = require("../utils/logger.js");
14
- const flow_structure_builder_js_1 = require("../utils/flow-structure-builder.js");
15
47
  class ServiceNowFlowComposerMCP {
16
48
  constructor() {
17
49
  this.server = new index_js_1.Server({
@@ -32,7 +64,7 @@ class ServiceNowFlowComposerMCP {
32
64
  tools: [
33
65
  {
34
66
  name: 'snow_create_flow',
35
- description: 'FULLY AUTONOMOUS flow creation - parses natural language, discovers artifacts, creates missing components, links everything, deploys automatically. ZERO MANUAL WORK!',
67
+ description: '🚀 PRIMARY FLOW TOOL - Create production-ready Flow Designer flows with XML-first approach and automatic deployment to ServiceNow. ZERO MANUAL STEPS!',
36
68
  inputSchema: {
37
69
  type: 'object',
38
70
  properties: {
@@ -297,30 +329,43 @@ class ServiceNowFlowComposerMCP {
297
329
  // 🧠 STEP 4: Generate complete flow definition
298
330
  const flowDefinition = await this.generateFlowDefinition(parsedIntent, templateMatch, artifacts);
299
331
  console.log('🧠 Generated flow definition:', JSON.stringify(flowDefinition, null, 2));
300
- // 🧠 STEP 5: Deploy if requested
332
+ // 🧠 STEP 5: Deploy using XML-first approach for maximum reliability
301
333
  let deploymentResult = null;
302
334
  if (args.deploy_immediately !== false) {
303
- console.log('🚀 DEPLOYING intelligent flow to ServiceNow...');
304
- // Use the conversion utility to ensure proper format
305
- const enhancedFlowDefinition = (0, flow_structure_builder_js_1.convertToFlowDefinition)({
306
- name: parsedIntent.flowName,
307
- description: parsedIntent.description,
308
- table: parsedIntent.table,
309
- trigger: parsedIntent.trigger,
310
- activities: flowDefinition.activities || [],
311
- variables: flowDefinition.variables || [],
312
- connections: flowDefinition.connections || [],
313
- error_handling: flowDefinition.error_handling || []
314
- });
315
- // Try enhanced method first, fallback to original if needed
335
+ console.log('🚀 DEPLOYING flow using XML-first approach...');
316
336
  try {
317
- deploymentResult = await this.client.createFlowWithStructureBuilder(enhancedFlowDefinition);
318
- console.log('🚀 Enhanced deployment result:', deploymentResult);
337
+ // Import the XML flow generator
338
+ const { generateProductionFlowXML } = await Promise.resolve().then(() => __importStar(require('../utils/xml-first-flow-generator.js')));
339
+ // Convert to XML flow definition format
340
+ const xmlFlowDef = {
341
+ name: parsedIntent.flowName,
342
+ description: parsedIntent.description,
343
+ table: parsedIntent.table,
344
+ trigger_type: this.mapTriggerTypeToXML(parsedIntent.trigger.type),
345
+ trigger_condition: parsedIntent.trigger.condition || '',
346
+ activities: this.convertActivitiesToXML(flowDefinition.activities || []),
347
+ run_as: 'user',
348
+ accessible_from: 'package_private'
349
+ };
350
+ // Generate production-ready XML
351
+ const xmlResult = generateProductionFlowXML(xmlFlowDef);
352
+ console.log('✅ XML generated:', xmlResult.filePath);
353
+ // Auto-deploy XML to ServiceNow
354
+ await this.deployXMLToServiceNow(xmlResult.filePath);
355
+ deploymentResult = {
356
+ success: true,
357
+ method: 'xml_first',
358
+ xml_file: xmlResult.filePath,
359
+ message: '✅ Flow deployed using XML-first approach!'
360
+ };
319
361
  }
320
- catch (enhancedError) {
321
- console.warn('⚠️ Enhanced deployment failed, falling back to original method:', enhancedError);
322
- deploymentResult = await this.client.createFlow(flowDefinition);
323
- console.log('🚀 Fallback deployment result:', deploymentResult);
362
+ catch (xmlError) {
363
+ console.warn('⚠️ XML deployment failed, providing manual instructions:', xmlError);
364
+ deploymentResult = {
365
+ success: false,
366
+ error: xmlError instanceof Error ? xmlError.message : String(xmlError),
367
+ fallback_instructions: 'Use snow-flow deploy-xml command for manual deployment'
368
+ };
324
369
  }
325
370
  }
326
371
  const credentials = await this.oauth.loadCredentials();
@@ -329,9 +374,9 @@ class ServiceNowFlowComposerMCP {
329
374
  content: [
330
375
  {
331
376
  type: 'text',
332
- text: `🎯 INTELLIGENT FLOW CREATED SUCCESSFULLY!
377
+ text: `🎯 FLOW CREATED WITH XML-FIRST APPROACH!
333
378
 
334
- ${args.deploy_immediately !== false ? `🚀 **LIVE DEPLOYMENT** - Real flow created in ServiceNow!` : `📋 **PLANNING MODE** - Flow structure generated`}
379
+ ${args.deploy_immediately !== false ? `🚀 **FULLY AUTOMATED DEPLOYMENT** - XML generated & deployed to ServiceNow!` : `📋 **PLANNING MODE** - Flow structure generated`}
335
380
 
336
381
  🧠 **Intelligent Analysis:**
337
382
  - **Flow Name**: ${parsedIntent.flowName}
@@ -347,26 +392,27 @@ ${args.deploy_immediately !== false ? `🚀 **LIVE DEPLOYMENT** - Real flow crea
347
392
  - **Error Handling**: ${flowDefinition.error_handling?.length || 0} safety measures
348
393
  - **Artifacts Used**: ${artifacts.existing.length} found, ${artifacts.created.length} created
349
394
 
350
- 🚀 **Deployment Status:**
351
- ${deploymentResult ? (deploymentResult.success ? '✅ Successfully deployed to ServiceNow!' : `❌ Deployment failed: ${deploymentResult.error}`) : '⏳ Ready for deployment'}
352
-
353
- ${deploymentResult?.success ? `🎯 **Live Flow Details:**
354
- - **System ID**: ${deploymentResult.data?.sys_id || 'Unknown'}
355
- - **Status**: ${deploymentResult.data?.status || 'Active'}
356
- - **URL**: ${deploymentResult.data?.url || flowUrl}` : ''}
395
+ 🚀 **XML-First Deployment:**
396
+ ${deploymentResult ? (deploymentResult.success ?
397
+ `✅ Successfully deployed using XML-first approach!
398
+ - **Method**: Production-ready Update Set XML
399
+ - **XML File**: ${deploymentResult.xml_file}
400
+ - **Status**: Imported → Previewed → Committed ✅` :
401
+ `❌ Auto-deployment failed: ${deploymentResult.error}
402
+ - **Fallback**: ${deploymentResult.fallback_instructions}`) : '⏳ Ready for deployment'}
357
403
 
358
404
  🔗 **ServiceNow Access:**
359
405
  - Flow Designer: ${flowUrl}
360
406
  - Flow Designer Home: https://${credentials?.instance}/flow-designer
361
407
 
362
- 🧠 **Intelligence Features:**
363
- - Natural language processing ✅
364
- - Template matching and adaptation ✅
365
- - Artifact discovery and reuse ✅
366
- - Complete flow definition generation ✅
367
- - Error handling and validation ✅
408
+ 🧠 **NEW Features (v1.3.17):**
409
+ - XML-first approach for maximum reliability ✅
410
+ - Automatic Update Set deployment ✅
411
+ - Zero manual steps required ✅
412
+ - Production-ready Flow Designer format ✅
413
+ - Intelligent error handling & fallbacks ✅
368
414
 
369
- Your flow is now intelligently crafted and ready for use! 🎉`,
415
+ Your flow is now live in ServiceNow Flow Designer! 🎉`,
370
416
  },
371
417
  ],
372
418
  };
@@ -1679,7 +1725,7 @@ ${flowInstruction.recommendations?.map((rec, index) => `${index + 1}. ${rec}`).j
1679
1725
 
1680
1726
  🚀 **Next Steps:**
1681
1727
  1. Use \`snow_template_matching\` to explore template options
1682
- 2. Run \`snow_create_flow\` to implement the recommended approach
1728
+ 2. Run \`snow_create_flow\` with deploy_immediately: true to implement the recommended approach
1683
1729
  3. Consider \`snow_scope_optimization\` for deployment strategy
1684
1730
 
1685
1731
  ✅ **Analysis Complete!** The instruction has been comprehensively analyzed with intelligent insights.`,
@@ -1841,7 +1887,7 @@ ${categoryFilteredResults.length === 0 ? `🔍 **No templates found matching you
1841
1887
  - **Recommended**: ${categoryFilteredResults[0]?.confidence >= 0.8 ? 'Yes - High confidence match' : 'Consider manual review'}
1842
1888
 
1843
1889
  🚀 **Next Steps:**
1844
- 1. Use \`snow_create_flow\` to implement the best matching template
1890
+ 1. Use \`snow_create_flow\` with deploy_immediately: true to implement the best matching template
1845
1891
  2. Review template customization options
1846
1892
  3. Consider \`snow_intelligent_flow_analysis\` for detailed analysis
1847
1893
  4. Modify instruction if no suitable templates found
@@ -1860,6 +1906,128 @@ ${categoryFilteredResults.length === 0 ? `🔍 **No templates found matching you
1860
1906
  await this.server.connect(transport);
1861
1907
  this.logger.info('ServiceNow Flow Composer MCP Server started');
1862
1908
  }
1909
+ /**
1910
+ * Map trigger type to XML format
1911
+ */
1912
+ mapTriggerTypeToXML(triggerType) {
1913
+ const mapping = {
1914
+ 'record_created': 'record_created',
1915
+ 'record_updated': 'record_updated',
1916
+ 'manual': 'manual',
1917
+ 'scheduled': 'scheduled',
1918
+ 'create': 'record_created',
1919
+ 'update': 'record_updated',
1920
+ 'on_create': 'record_created',
1921
+ 'on_update': 'record_updated'
1922
+ };
1923
+ return mapping[triggerType.toLowerCase()] || 'manual';
1924
+ }
1925
+ /**
1926
+ * Convert activities to XML format
1927
+ */
1928
+ convertActivitiesToXML(activities) {
1929
+ return activities.map((activity, index) => ({
1930
+ type: this.mapActivityTypeToXML(activity.type),
1931
+ name: activity.name || `Activity ${index + 1}`,
1932
+ inputs: activity.inputs || {},
1933
+ order: (index + 1) * 100,
1934
+ description: activity.description || activity.name
1935
+ }));
1936
+ }
1937
+ /**
1938
+ * Map activity type to XML format
1939
+ */
1940
+ mapActivityTypeToXML(activityType) {
1941
+ const mapping = {
1942
+ 'approval': 'approval',
1943
+ 'notification': 'notification',
1944
+ 'email': 'notification',
1945
+ 'script': 'script',
1946
+ 'create_record': 'create_record',
1947
+ 'update_record': 'update_record',
1948
+ 'rest_call': 'rest_step',
1949
+ 'condition': 'condition',
1950
+ 'subflow': 'assign_subflow'
1951
+ };
1952
+ return mapping[activityType.toLowerCase()] || 'script';
1953
+ }
1954
+ /**
1955
+ * Deploy XML file to ServiceNow automatically
1956
+ */
1957
+ async deployXMLToServiceNow(xmlFilePath) {
1958
+ // Check authentication
1959
+ const isAuth = await this.oauth.isAuthenticated();
1960
+ if (!isAuth) {
1961
+ throw new Error('Not authenticated with ServiceNow. Please run: snow-flow auth login');
1962
+ }
1963
+ // Initialize ServiceNow client
1964
+ const ServiceNowClient = (await Promise.resolve().then(() => __importStar(require('../utils/servicenow-client.js')))).ServiceNowClient;
1965
+ const client = new ServiceNowClient();
1966
+ // Read the XML file
1967
+ const fs = require('fs').promises;
1968
+ const xmlContent = await fs.readFile(xmlFilePath, 'utf-8');
1969
+ // Import XML as remote update set
1970
+ const importResponse = await client.makeRequest({
1971
+ method: 'POST',
1972
+ url: '/api/now/table/sys_remote_update_set',
1973
+ headers: {
1974
+ 'Content-Type': 'application/xml',
1975
+ 'Accept': 'application/json'
1976
+ },
1977
+ data: xmlContent
1978
+ });
1979
+ if (!importResponse.result || !importResponse.result.sys_id) {
1980
+ throw new Error('Failed to import XML update set');
1981
+ }
1982
+ const remoteUpdateSetId = importResponse.result.sys_id;
1983
+ this.logger.info(`✅ XML imported successfully (sys_id: ${remoteUpdateSetId})`);
1984
+ // Load the update set
1985
+ await client.makeRequest({
1986
+ method: 'PUT',
1987
+ url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
1988
+ data: {
1989
+ state: 'loaded'
1990
+ }
1991
+ });
1992
+ // Find the loaded update set
1993
+ const loadedResponse = await client.makeRequest({
1994
+ method: 'GET',
1995
+ url: '/api/now/table/sys_update_set',
1996
+ params: {
1997
+ sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
1998
+ sysparm_limit: 1
1999
+ }
2000
+ });
2001
+ if (!loadedResponse.result || loadedResponse.result.length === 0) {
2002
+ throw new Error('Failed to find loaded update set');
2003
+ }
2004
+ const updateSetId = loadedResponse.result[0].sys_id;
2005
+ const updateSetName = loadedResponse.result[0].name;
2006
+ // Preview the update set
2007
+ await client.makeRequest({
2008
+ method: 'POST',
2009
+ url: `/api/now/table/sys_update_set/${updateSetId}/preview`
2010
+ });
2011
+ // Check for preview problems
2012
+ const previewProblems = await client.makeRequest({
2013
+ method: 'GET',
2014
+ url: '/api/now/table/sys_update_preview_problem',
2015
+ params: {
2016
+ sysparm_query: `update_set=${updateSetId}`,
2017
+ sysparm_limit: 100
2018
+ }
2019
+ });
2020
+ if (previewProblems.result && previewProblems.result.length > 0) {
2021
+ const problemsList = previewProblems.result.map((p) => `- ${p.type}: ${p.description}`).join('\n');
2022
+ throw new Error(`Preview found problems:\n${problemsList}\n\nPlease review and resolve in ServiceNow UI`);
2023
+ }
2024
+ // Commit the update set
2025
+ await client.makeRequest({
2026
+ method: 'POST',
2027
+ url: `/api/now/table/sys_update_set/${updateSetId}/commit`
2028
+ });
2029
+ this.logger.info(`✅ Update set committed successfully: ${updateSetName}`);
2030
+ }
1863
2031
  }
1864
2032
  // Start the server
1865
2033
  const server = new ServiceNowFlowComposerMCP();
@@ -302,6 +302,24 @@ class ServiceNowPlatformDevelopmentMCP {
302
302
  async getTableInfo(tableName) {
303
303
  try {
304
304
  this.logger.debug(`Looking up table info for: ${tableName}`);
305
+ // First, check if this is a known standard table that may not appear in sys_db_object
306
+ const standardTables = {
307
+ 'incident': { label: 'Incident' },
308
+ 'problem': { label: 'Problem' },
309
+ 'change_request': { label: 'Change Request' },
310
+ 'sc_request': { label: 'Request' },
311
+ 'sc_req_item': { label: 'Requested Item' },
312
+ 'sc_task': { label: 'Catalog Task' },
313
+ 'task': { label: 'Task' }
314
+ };
315
+ if (standardTables[tableName]) {
316
+ this.logger.debug(`Using known standard table: ${tableName}`);
317
+ return {
318
+ name: tableName,
319
+ label: standardTables[tableName].label,
320
+ sys_id: `standard_table_${tableName}` // Placeholder sys_id for standard tables
321
+ };
322
+ }
305
323
  // Try direct lookup first
306
324
  const tableResponse = await this.client.searchRecords('sys_db_object', `name=${tableName}`, 1);
307
325
  if (tableResponse.success && tableResponse.data?.result?.length > 0) {
@@ -312,6 +330,8 @@ class ServiceNowPlatformDevelopmentMCP {
312
330
  sys_id: table.sys_id
313
331
  };
314
332
  }
333
+ // Log the actual response for debugging
334
+ this.logger.debug(`Table lookup response for ${tableName}: ${JSON.stringify(tableResponse)}`);
315
335
  // Try by sys_id
316
336
  const tableByIdResponse = await this.client.searchRecords('sys_db_object', `sys_id=${tableName}`, 1);
317
337
  if (tableByIdResponse.success && tableByIdResponse.data?.result?.length > 0) {
@@ -583,10 +603,15 @@ class ServiceNowPlatformDevelopmentMCP {
583
603
  this.logger.debug(`Found table info: ${JSON.stringify(tableInfo)}`);
584
604
  // Get detailed table metadata
585
605
  this.logger.debug(`Attempting to fetch table details for sys_id: ${tableInfo.sys_id}`);
586
- const tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
606
+ // Check if this is a standard table with placeholder sys_id
607
+ const isStandardTable = tableInfo.sys_id.startsWith('standard_table_');
608
+ let tableDetailsResponse = { success: false };
609
+ if (!isStandardTable) {
610
+ tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
611
+ }
587
612
  // Declare the variable once with proper type
588
613
  let tableDetails;
589
- if (!tableDetailsResponse.success) {
614
+ if (!tableDetailsResponse.success || isStandardTable) {
590
615
  const errorMessage = tableDetailsResponse.error ||
591
616
  JSON.stringify(tableDetailsResponse) ||
592
617
  'Unknown error occurred while fetching table details';
@@ -187,6 +187,10 @@ class ServiceNowUpdateSetMCP extends base_mcp_server_js_1.BaseMCPServer {
187
187
  url: '/api/now/table/sys_update_set',
188
188
  data: updateSetData
189
189
  });
190
+ // Validate response structure
191
+ if (!response || !response.result) {
192
+ throw new Error(`Invalid API response: ${JSON.stringify(response)}`);
193
+ }
190
194
  const updateSet = response.result;
191
195
  // Create session
192
196
  const session = {
@@ -276,6 +276,10 @@ class ServiceNowUpdateSetMCP {
276
276
  if (!response.success) {
277
277
  throw new Error(response.error || 'Failed to create Update Set');
278
278
  }
279
+ // Validate response structure
280
+ if (!response.data || !response.data.sys_id) {
281
+ throw new Error(`Invalid Update Set response: missing data or sys_id. Response: ${JSON.stringify(response)}`);
282
+ }
279
283
  // Auto-switch to Update Set if requested (default: true)
280
284
  const autoSwitch = args.auto_switch !== false;
281
285
  let switchedToUpdateSet = false;