execute_updateset_operation
Manage ServiceNow update set lifecycle operations including creation, tracking, XML reassignment, and data modifications in sandbox environments with automatic pagination for large datasets.
Instructions
Manage ServiceNow update sets with lifecycle operations, XML reassignment, and working set tracking. ⚠️ SANDBOX ONLY - modifies update sets. 🛡️ Auto-limits large results. Use pagination for big datasets. 📁 Use {{file:path}} for large data.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | The update set operation to perform. Required. | |
| name | No | Update set name (required for create operation). | |
| description | No | Update set description (optional for create operation). | |
| scope | No | Update set scope (optional, defaults to configured scope). | |
| set_as_working | No | Set the created update set as working set (for create operation). | |
| update_set_sys_id | No | Update set sys_id for operations that require it. | |
| table | No | Table name for insert/update operations. | |
| sys_id | No | Record sys_id for update operations. | |
| data | No | Record data for insert/update operations. Can be single object or array for batch operations. Supports {{file:...}} placeholders to load content from local files. | |
| batch | No | Enable batch mode for multiple record operations. | |
| xml_sys_ids | No | Array of XML sys_ids for rehome operations. | |
| query | No | ServiceNow encoded query string for rehome operations. | |
| force | No | Force reassignment even if XML is not in Default update set. | |
| limit | No | Maximum number of records to return for list/recent operations. | |
| offset | No | Number of records to skip for pagination. | |
| filters | No | Filters for list operations (scope, state, created_by, sys_created_on). | |
| response_mode | No | Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full | |
| quiet | No | Compact acknowledgment for update operations to avoid RESPONSE_TOO_LARGE errors. Default: false. |
Implementation Reference
- src/index.ts:397-576 (handler)MCP server tool handler for 'execute_updateset_operation'. Validates input, resolves file placeholders, calls the update set client, applies context overflow protection, and returns JSON response.if (request.params.name === 'execute_updateset_operation') { try { // Check if update set client was initialized successfully if (!updateSetClient) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: { code: 'INITIALIZATION_ERROR', message: 'ServiceNow update set client failed to initialize', details: initError instanceof Error ? initError.message : 'Unknown error', }, }), }, ], isError: true, }; } // Extract parameters from tool arguments const args = request.params.arguments as Record<string, unknown> | undefined; const operation = args?.operation as string | undefined; const name = args?.name as string | undefined; const description = args?.description as string | undefined; const scope = args?.scope as string | undefined; const setAsWorking = args?.set_as_working as boolean | undefined; const updateSetSysId = args?.update_set_sys_id as string | undefined; const table = args?.table as string | undefined; const sysId = args?.sys_id as string | undefined; const data = args?.data as Record<string, any> | Record<string, any>[] | undefined; const batch = args?.batch as boolean | undefined; const xmlSysIds = args?.xml_sys_ids as string[] | undefined; const query = args?.query as string | undefined; const force = args?.force as boolean | undefined; const limit = args?.limit as number | undefined; const offset = args?.offset as number | undefined; const filters = args?.filters as Record<string, any> | undefined; const responseMode = args?.response_mode as string | undefined; const quiet = args?.quiet as boolean | undefined; // Validate required parameters if (!operation) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: { code: UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, message: 'Required parameter "operation" is missing', details: 'Please provide the operation type (create, set_working, show_working, clear_working, insert, update, rehome, contents, recent, list, info, complete, reopen, delete, diff_default)', }, }), }, ], isError: true, }; } // Resolve file placeholders in the request arguments let resolvedArgs = { operation: operation as any, name, description, scope, set_as_working: setAsWorking, update_set_sys_id: updateSetSysId, table, sys_id: sysId, data, batch, xml_sys_ids: xmlSysIds, query, force, limit, offset, filters, response_mode: responseMode as any, quiet, }; try { const resolution = resolveFilePlaceholders(resolvedArgs); resolvedArgs = resolution.data; } catch (error) { if (error instanceof FilePlaceholderError) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: { code: 'FILE_PLACEHOLDER_ERROR', message: 'Failed to resolve file placeholder', details: `${error.placeholder}: ${error.message}`, }, }), }, ], isError: true, }; } // Re-throw unknown errors throw error; } // Set timestamp after file placeholder resolution for accurate XML detection // Subtract 500ms to account for timing between placeholder resolution and record creation const timestampBefore = Date.now() - 500; // Execute the update set operation const result = await updateSetClient.executeUpdateSetOperation({ operation: resolvedArgs.operation, name: resolvedArgs.name, description: resolvedArgs.description, scope: resolvedArgs.scope, set_as_working: resolvedArgs.set_as_working, update_set_sys_id: resolvedArgs.update_set_sys_id, table: resolvedArgs.table, sys_id: resolvedArgs.sys_id, data: resolvedArgs.data, batch: resolvedArgs.batch, xml_sys_ids: resolvedArgs.xml_sys_ids, query: resolvedArgs.query, force: resolvedArgs.force, limit: resolvedArgs.limit, offset: resolvedArgs.offset, filters: resolvedArgs.filters, custom_timestamp_before: timestampBefore, response_mode: responseMode as any, quiet: resolvedArgs.quiet, }); // Apply global context overflow prevention const { response: protectedResult, monitoring } = globalContextOverflowPrevention.monitorResponse(result, 'execute_updateset_operation', responseMode); return { content: [ { type: 'text', text: JSON.stringify(protectedResult, null, 2), }, ], }; } catch (error) { const errorResponse = { success: false, error: { code: 'UNKNOWN_ERROR', message: 'An unexpected error occurred', details: undefined as string | undefined, }, }; if (error instanceof ServiceNowUpdateSetError) { errorResponse.error.code = error.code; errorResponse.error.message = error.message; errorResponse.error.details = `HTTP Status: ${error.statusCode || 'N/A'}`; } else if (error instanceof Error) { errorResponse.error.message = error.message; } return { content: [ { type: 'text', text: JSON.stringify(errorResponse), }, ], isError: true, }; }
- Core ServiceNowUpdateSetClient.executeUpdateSetOperation method. Main entry point that validates requests and routes to specific update set operations like create, insert, rehome, etc.async executeUpdateSetOperation(request: UpdateSetOperationRequest): Promise<UpdateSetOperationResult> { const startTime = Date.now(); try { // Validate input this.validateUpdateSetRequest(request); // Route to appropriate operation let result: any; let metadata: any = { operation: request.operation, executionTime: 0, timestamp: new Date().toISOString(), working_set: this.workingUpdateSet, }; switch (request.operation) { case 'create': result = await this.createUpdateSet(request); if (request.set_as_working && result.update_set) { this.setWorkingSet(result.update_set); result.working_set = this.workingUpdateSet; } break; case 'set_working': if (!request.update_set_sys_id) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'update_set_sys_id is required for set_working operation' ); } const updateSet = await this.getUpdateSetInfo(request.update_set_sys_id); this.setWorkingSet(updateSet); result = { working_set: this.workingUpdateSet }; break; case 'show_working': result = { working_set: this.workingUpdateSet }; break; case 'clear_working': this.clearWorkingSet(); result = { working_set: null }; break; case 'insert': if (!request.table || !request.data) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'table and data are required for insert operation' ); } result = await this.insertWithReassignment( request.table, request.data as Record<string, any>, request.update_set_sys_id, request.custom_timestamp_before ); break; case 'update': if (!request.table || !request.sys_id || !request.data) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'table, sys_id, and data are required for update operation' ); } result = await this.updateWithReassignment( request.table, request.sys_id, request.data as Record<string, any>, request.update_set_sys_id, request.custom_timestamp_before ); break; case 'rehome': if (!request.xml_sys_ids && !request.query) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'xml_sys_ids or query is required for rehome operation' ); } if (request.xml_sys_ids) { result = await this.rehomeXMLByIds( request.xml_sys_ids, request.update_set_sys_id || this.getWorkingSetId(), request.force || false ); } else { result = await this.rehomeXMLByQuery( request.query!, request.update_set_sys_id || this.getWorkingSetId(), request.force || false ); } break; case 'contents': result = await this.getUpdateSetContents( request.update_set_sys_id || this.getWorkingSetId(), request.response_mode ); break; case 'recent': result = await this.getRecentXML(request.limit || 50, request.response_mode); break; case 'list': result = await this.listUpdateSets(request.filters, request.limit, request.offset); break; case 'info': if (!request.update_set_sys_id) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'update_set_sys_id is required for info operation' ); } result = { update_set: await this.getUpdateSetInfo(request.update_set_sys_id) }; break; case 'complete': if (!request.update_set_sys_id) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'update_set_sys_id is required for complete operation' ); } result = await this.completeUpdateSet(request.update_set_sys_id); break; case 'reopen': if (!request.update_set_sys_id) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'update_set_sys_id is required for reopen operation' ); } // Check if state changes are disabled if (process.env.SKYENET_UPDATESET_DISABLE_STATE_CHANGES === 'true') { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.OPERATION_DISABLED, undefined, 'Reopen operation is disabled due to ServiceNow business rule limitations. Use create, list, contents, recent, diff, and complete operations instead.' ); } result = await this.reopenUpdateSet(request.update_set_sys_id); break; case 'delete': if (!request.update_set_sys_id) { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.MISSING_PARAMETER, undefined, 'update_set_sys_id is required for delete operation' ); } // Check if state changes are disabled if (process.env.SKYENET_UPDATESET_DISABLE_STATE_CHANGES === 'true') { throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.OPERATION_DISABLED, undefined, 'Delete operation is disabled due to ServiceNow business rule limitations. Use create, list, contents, recent, diff, and complete operations instead.' ); } result = await this.deleteUpdateSet(request.update_set_sys_id); break; case 'diff_default': result = await this.diffAgainstDefault( request.update_set_sys_id || this.getWorkingSetId(), request.response_mode ); break; default: throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.INVALID_OPERATION, undefined, `Invalid operation: ${request.operation}` ); } const executionTime = Date.now() - startTime; metadata.executionTime = executionTime; // Estimate response size for metadata const responseSize = JSON.stringify(result).length; metadata.responseSize = responseSize; metadata.contextOverflowPrevention = responseSize > 40000; // 40KB threshold // Handle quiet mode for update operations - ultra-minimal response if (request.quiet && (request.operation === 'insert' || request.operation === 'update' || request.operation === 'set_working')) { return { success: true, data: { message: 'Update accepted' }, metadata: { operation: request.operation, executionTime: 0, timestamp: new Date().toISOString(), quiet_mode: true } }; } return { success: true, data: result, metadata, }; } catch (error) { if (error instanceof ServiceNowUpdateSetError) { throw error; } throw new ServiceNowUpdateSetError( UPDATE_SET_ERROR_CODES.NETWORK_ERROR, undefined, `Update set operation failed: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }
- src/index.ts:702-787 (registration)Tool registration in MCP server's listTools handler, defining name, description, and full input schema with all parameters and enums.{ name: 'execute_updateset_operation', description: 'Manage ServiceNow update sets with lifecycle operations, XML reassignment, and working set tracking. ⚠️ SANDBOX ONLY - modifies update sets. 🛡️ Auto-limits large results. Use pagination for big datasets. 📁 Use {{file:path}} for large data.', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['create', 'set_working', 'show_working', 'clear_working', 'insert', 'update', 'rehome', 'contents', 'recent', 'list', 'info', 'complete', 'reopen', 'delete', 'diff_default'], description: 'The update set operation to perform. Required.', }, name: { type: 'string', description: 'Update set name (required for create operation).', }, description: { type: 'string', description: 'Update set description (optional for create operation).', }, scope: { type: 'string', description: 'Update set scope (optional, defaults to configured scope).', }, set_as_working: { type: 'boolean', description: 'Set the created update set as working set (for create operation).', }, update_set_sys_id: { type: 'string', description: 'Update set sys_id for operations that require it.', }, table: { type: 'string', description: 'Table name for insert/update operations.', }, sys_id: { type: 'string', description: 'Record sys_id for update operations.', }, data: { type: 'object', description: 'Record data for insert/update operations. Can be single object or array for batch operations. Supports {{file:...}} placeholders to load content from local files.', }, batch: { type: 'boolean', description: 'Enable batch mode for multiple record operations.', }, xml_sys_ids: { type: 'array', items: { type: 'string' }, description: 'Array of XML sys_ids for rehome operations.', }, query: { type: 'string', description: 'ServiceNow encoded query string for rehome operations.', }, force: { type: 'boolean', description: 'Force reassignment even if XML is not in Default update set.', }, limit: { type: 'number', description: 'Maximum number of records to return for list/recent operations.', }, offset: { type: 'number', description: 'Number of records to skip for pagination.', }, filters: { type: 'object', description: 'Filters for list operations (scope, state, created_by, sys_created_on).', }, response_mode: { type: 'string', enum: ['full', 'minimal', 'compact'], description: 'Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full', }, quiet: { type: 'boolean', description: 'Compact acknowledgment for update operations to avoid RESPONSE_TOO_LARGE errors. Default: false.', }, }, required: ['operation'], }, },
- TypeScript type imports for UpdateSetOperationRequest and UpdateSetOperationResult used for input/output validation in the handler.UpdateSetOperationRequest, UpdateSetOperationResult, UpdateSetErrorResponse, UpdateSetRecord, XMLRecord, WorkingSetState, UpdateSetContents, RecentXMLActivity, UpdateSetDiff, XMLSummary, XMLDetectionResult, XMLReassignmentResult, UpdateSetFilters, UpdateSetClientConfig, DEFAULT_UPDATE_SET_CONFIG, loadUpdateSetConfig, ServiceNowUpdateSetError, UPDATE_SET_ERROR_CODES, isWorkingSetState, isUpdateSetRecord, isXMLRecord, } from './updateSetTypes.js';