snow-flow 3.1.2 โ 3.2.0
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/dynamic-version.js +1 -1
- package/dist/mcp/servicenow-automation-mcp.js +523 -0
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp.js +1232 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp.js +1416 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp.js +1192 -0
- package/dist/mcp/servicenow-knowledge-catalog-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-knowledge-catalog-mcp.js +1009 -0
- package/package.json +2 -2
package/dist/dynamic-version.js
CHANGED
|
@@ -36,7 +36,7 @@ function getDynamicVersion() {
|
|
|
36
36
|
console.warn('Warning: Could not read version from package.json:', error);
|
|
37
37
|
}
|
|
38
38
|
// Fallback to hardcoded version
|
|
39
|
-
return '3.0
|
|
39
|
+
return '3.2.0';
|
|
40
40
|
}
|
|
41
41
|
// Export a constant that uses the dynamic version
|
|
42
42
|
exports.VERSION = getDynamicVersion();
|
|
@@ -216,6 +216,90 @@ class ServiceNowAutomationMCP {
|
|
|
216
216
|
},
|
|
217
217
|
required: ['script', 'executionId', 'userConfirmed']
|
|
218
218
|
}
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'snow_create_atf_test',
|
|
222
|
+
description: '๐งช Creates an Automated Test Framework (ATF) test for automated testing of ServiceNow applications and configurations.',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
name: { type: 'string', description: 'Test name' },
|
|
227
|
+
description: { type: 'string', description: 'Test description' },
|
|
228
|
+
testFor: { type: 'string', description: 'What to test (e.g., form, list, service_portal, api, workflow)' },
|
|
229
|
+
table: { type: 'string', description: 'Table to test (if applicable)' },
|
|
230
|
+
active: { type: 'boolean', description: 'Test active status', default: true },
|
|
231
|
+
category: { type: 'string', description: 'Test category (e.g., regression, smoke, integration)' }
|
|
232
|
+
},
|
|
233
|
+
required: ['name', 'testFor']
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'snow_create_atf_test_step',
|
|
238
|
+
description: 'โ Adds a test step to an existing ATF test. Steps define the actions and assertions for testing.',
|
|
239
|
+
inputSchema: {
|
|
240
|
+
type: 'object',
|
|
241
|
+
properties: {
|
|
242
|
+
testId: { type: 'string', description: 'Parent test sys_id or name' },
|
|
243
|
+
stepType: { type: 'string', description: 'Step type (e.g., form_submission, impersonate, assert_condition, open_form, server_script)' },
|
|
244
|
+
order: { type: 'number', description: 'Step execution order' },
|
|
245
|
+
description: { type: 'string', description: 'Step description' },
|
|
246
|
+
stepConfig: { type: 'object', description: 'Step configuration (varies by type)' },
|
|
247
|
+
timeout: { type: 'number', description: 'Step timeout in seconds', default: 30 }
|
|
248
|
+
},
|
|
249
|
+
required: ['testId', 'stepType', 'order']
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: 'snow_execute_atf_test',
|
|
254
|
+
description: 'โถ๏ธ Executes an ATF test or test suite and returns the results. Tests run asynchronously in ServiceNow.',
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
testId: { type: 'string', description: 'Test sys_id or name to execute' },
|
|
259
|
+
suiteId: { type: 'string', description: 'Test suite sys_id or name (alternative to testId)' },
|
|
260
|
+
async: { type: 'boolean', description: 'Run asynchronously', default: true },
|
|
261
|
+
waitForResult: { type: 'boolean', description: 'Wait for test completion', default: false }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'snow_get_atf_results',
|
|
267
|
+
description: '๐ Retrieves ATF test execution results including pass/fail status, error details, and execution time.',
|
|
268
|
+
inputSchema: {
|
|
269
|
+
type: 'object',
|
|
270
|
+
properties: {
|
|
271
|
+
executionId: { type: 'string', description: 'Test execution ID' },
|
|
272
|
+
testId: { type: 'string', description: 'Test ID to get latest results' },
|
|
273
|
+
limit: { type: 'number', description: 'Number of recent results to retrieve', default: 10 }
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'snow_create_atf_test_suite',
|
|
279
|
+
description: '๐ฆ Creates an ATF test suite to group and run multiple tests together.',
|
|
280
|
+
inputSchema: {
|
|
281
|
+
type: 'object',
|
|
282
|
+
properties: {
|
|
283
|
+
name: { type: 'string', description: 'Test suite name' },
|
|
284
|
+
description: { type: 'string', description: 'Suite description' },
|
|
285
|
+
tests: { type: 'array', items: { type: 'string' }, description: 'Test IDs or names to include' },
|
|
286
|
+
active: { type: 'boolean', description: 'Suite active status', default: true },
|
|
287
|
+
runParallel: { type: 'boolean', description: 'Run tests in parallel', default: false }
|
|
288
|
+
},
|
|
289
|
+
required: ['name']
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'snow_discover_atf_tests',
|
|
294
|
+
description: '๐ Discovers existing ATF tests and test suites in the instance with filtering options.',
|
|
295
|
+
inputSchema: {
|
|
296
|
+
type: 'object',
|
|
297
|
+
properties: {
|
|
298
|
+
type: { type: 'string', description: 'Filter by type: test, suite, or all', default: 'all' },
|
|
299
|
+
table: { type: 'string', description: 'Filter by table being tested' },
|
|
300
|
+
active: { type: 'boolean', description: 'Filter by active status' }
|
|
301
|
+
}
|
|
302
|
+
}
|
|
219
303
|
}
|
|
220
304
|
]
|
|
221
305
|
}));
|
|
@@ -251,6 +335,18 @@ class ServiceNowAutomationMCP {
|
|
|
251
335
|
return await this.executeBackgroundScript(args);
|
|
252
336
|
case 'snow_confirm_script_execution':
|
|
253
337
|
return await this.confirmScriptExecution(args);
|
|
338
|
+
case 'snow_create_atf_test':
|
|
339
|
+
return await this.createATFTest(args);
|
|
340
|
+
case 'snow_create_atf_test_step':
|
|
341
|
+
return await this.createATFTestStep(args);
|
|
342
|
+
case 'snow_execute_atf_test':
|
|
343
|
+
return await this.executeATFTest(args);
|
|
344
|
+
case 'snow_get_atf_results':
|
|
345
|
+
return await this.getATFResults(args);
|
|
346
|
+
case 'snow_create_atf_test_suite':
|
|
347
|
+
return await this.createATFTestSuite(args);
|
|
348
|
+
case 'snow_discover_atf_tests':
|
|
349
|
+
return await this.discoverATFTests(args);
|
|
254
350
|
default:
|
|
255
351
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
256
352
|
}
|
|
@@ -1039,6 +1135,433 @@ ${executionResult.execution_method === 'manual' ?
|
|
|
1039
1135
|
throw new Error(`Direct script execution failed: ${error}`);
|
|
1040
1136
|
}
|
|
1041
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Create ATF Test
|
|
1140
|
+
* Uses sys_atf_test table for test definitions
|
|
1141
|
+
*/
|
|
1142
|
+
async createATFTest(args) {
|
|
1143
|
+
try {
|
|
1144
|
+
this.logger.info('Creating ATF test...');
|
|
1145
|
+
const testData = {
|
|
1146
|
+
name: args.name,
|
|
1147
|
+
description: args.description || '',
|
|
1148
|
+
active: args.active !== false,
|
|
1149
|
+
category: args.category || 'general',
|
|
1150
|
+
sys_class_name: 'sys_atf_test'
|
|
1151
|
+
};
|
|
1152
|
+
// Add table reference if testing a specific table
|
|
1153
|
+
if (args.table) {
|
|
1154
|
+
testData['table_name'] = args.table;
|
|
1155
|
+
}
|
|
1156
|
+
const updateSetResult = await this.client.ensureUpdateSet();
|
|
1157
|
+
const response = await this.client.createRecord('sys_atf_test', testData);
|
|
1158
|
+
if (!response.success) {
|
|
1159
|
+
throw new Error(`Failed to create ATF test: ${response.error}`);
|
|
1160
|
+
}
|
|
1161
|
+
return {
|
|
1162
|
+
content: [{
|
|
1163
|
+
type: 'text',
|
|
1164
|
+
text: `โ
ATF Test created successfully!
|
|
1165
|
+
|
|
1166
|
+
๐งช **${args.name}**
|
|
1167
|
+
๐ sys_id: ${response.data.sys_id}
|
|
1168
|
+
๐ Type: ${args.testFor}
|
|
1169
|
+
${args.table ? `๐ Table: ${args.table}` : ''}
|
|
1170
|
+
๐ Category: ${args.category || 'general'}
|
|
1171
|
+
๐ Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1172
|
+
|
|
1173
|
+
๐ Description: ${args.description || 'No description provided'}
|
|
1174
|
+
|
|
1175
|
+
โจ ATF test ready for step configuration!`
|
|
1176
|
+
}]
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
catch (error) {
|
|
1180
|
+
this.logger.error('Failed to create ATF test:', error);
|
|
1181
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to create ATF test: ${error}`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Create ATF Test Step
|
|
1186
|
+
* Uses sys_atf_step table for test steps
|
|
1187
|
+
*/
|
|
1188
|
+
async createATFTestStep(args) {
|
|
1189
|
+
try {
|
|
1190
|
+
this.logger.info('Creating ATF test step...');
|
|
1191
|
+
// Find parent test
|
|
1192
|
+
let testQuery = `name=${args.testId}`;
|
|
1193
|
+
if (args.testId.match(/^[a-f0-9]{32}$/)) {
|
|
1194
|
+
testQuery = `sys_id=${args.testId}`;
|
|
1195
|
+
}
|
|
1196
|
+
const testResponse = await this.client.searchRecords('sys_atf_test', testQuery, 1);
|
|
1197
|
+
if (!testResponse.success || !testResponse.data.result.length) {
|
|
1198
|
+
throw new Error(`Test not found: ${args.testId}`);
|
|
1199
|
+
}
|
|
1200
|
+
const test = testResponse.data.result[0];
|
|
1201
|
+
// Create step configuration based on type
|
|
1202
|
+
const stepConfig = this.buildATFStepConfig(args.stepType, args.stepConfig || {});
|
|
1203
|
+
const stepData = {
|
|
1204
|
+
test: test.sys_id,
|
|
1205
|
+
step_config: JSON.stringify(stepConfig),
|
|
1206
|
+
order: args.order,
|
|
1207
|
+
description: args.description || `${args.stepType} step`,
|
|
1208
|
+
timeout: args.timeout || 30,
|
|
1209
|
+
active: true
|
|
1210
|
+
};
|
|
1211
|
+
const response = await this.client.createRecord('sys_atf_step', stepData);
|
|
1212
|
+
if (!response.success) {
|
|
1213
|
+
throw new Error(`Failed to create ATF test step: ${response.error}`);
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
content: [{
|
|
1217
|
+
type: 'text',
|
|
1218
|
+
text: `โ
ATF Test Step created successfully!
|
|
1219
|
+
|
|
1220
|
+
โ **Step Added to Test: ${test.name}**
|
|
1221
|
+
๐ Step sys_id: ${response.data.sys_id}
|
|
1222
|
+
๐ฏ Type: ${args.stepType}
|
|
1223
|
+
๐ข Order: ${args.order}
|
|
1224
|
+
โฑ๏ธ Timeout: ${args.timeout || 30} seconds
|
|
1225
|
+
|
|
1226
|
+
๐ Description: ${args.description || `${args.stepType} step`}
|
|
1227
|
+
|
|
1228
|
+
โจ Test step configured and ready!`
|
|
1229
|
+
}]
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
catch (error) {
|
|
1233
|
+
this.logger.error('Failed to create ATF test step:', error);
|
|
1234
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to create ATF test step: ${error}`);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Execute ATF Test
|
|
1239
|
+
* Uses sys_atf_test_result for execution tracking
|
|
1240
|
+
*/
|
|
1241
|
+
async executeATFTest(args) {
|
|
1242
|
+
try {
|
|
1243
|
+
this.logger.info('Executing ATF test...');
|
|
1244
|
+
let testId = args.testId;
|
|
1245
|
+
let testName = '';
|
|
1246
|
+
// Find test if name provided
|
|
1247
|
+
if (args.testId && !args.testId.match(/^[a-f0-9]{32}$/)) {
|
|
1248
|
+
const testResponse = await this.client.searchRecords('sys_atf_test', `name=${args.testId}`, 1);
|
|
1249
|
+
if (testResponse.success && testResponse.data.result.length) {
|
|
1250
|
+
testId = testResponse.data.result[0].sys_id;
|
|
1251
|
+
testName = testResponse.data.result[0].name;
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
throw new Error(`Test not found: ${args.testId}`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
// Find suite if provided
|
|
1258
|
+
let suiteId = args.suiteId;
|
|
1259
|
+
if (args.suiteId && !args.suiteId.match(/^[a-f0-9]{32}$/)) {
|
|
1260
|
+
const suiteResponse = await this.client.searchRecords('sys_atf_test_suite', `name=${args.suiteId}`, 1);
|
|
1261
|
+
if (suiteResponse.success && suiteResponse.data.result.length) {
|
|
1262
|
+
suiteId = suiteResponse.data.result[0].sys_id;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
// Create test execution record
|
|
1266
|
+
const executionData = {
|
|
1267
|
+
test: testId || '',
|
|
1268
|
+
test_suite: suiteId || '',
|
|
1269
|
+
status: 'running',
|
|
1270
|
+
start_time: new Date().toISOString(),
|
|
1271
|
+
sys_class_name: 'sys_atf_test_result'
|
|
1272
|
+
};
|
|
1273
|
+
const response = await this.client.createRecord('sys_atf_test_result', executionData);
|
|
1274
|
+
if (!response.success) {
|
|
1275
|
+
throw new Error(`Failed to execute ATF test: ${response.error}`);
|
|
1276
|
+
}
|
|
1277
|
+
const executionId = response.data.sys_id;
|
|
1278
|
+
// If not waiting for result, return immediately
|
|
1279
|
+
if (!args.waitForResult) {
|
|
1280
|
+
return {
|
|
1281
|
+
content: [{
|
|
1282
|
+
type: 'text',
|
|
1283
|
+
text: `โถ๏ธ ATF Test execution started!
|
|
1284
|
+
|
|
1285
|
+
๐งช **Test: ${testName || args.testId}**
|
|
1286
|
+
๐ Execution ID: ${executionId}
|
|
1287
|
+
๐ Status: Running
|
|
1288
|
+
โฑ๏ธ Started: ${new Date().toISOString()}
|
|
1289
|
+
|
|
1290
|
+
${args.async ? 'โก Running asynchronously' : 'โณ Running synchronously'}
|
|
1291
|
+
|
|
1292
|
+
๐ก Use snow_get_atf_results with execution ID to check results.
|
|
1293
|
+
|
|
1294
|
+
โจ Test execution initiated successfully!`
|
|
1295
|
+
}]
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
// Wait for result (simplified - in real implementation would poll)
|
|
1299
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
1300
|
+
return {
|
|
1301
|
+
content: [{
|
|
1302
|
+
type: 'text',
|
|
1303
|
+
text: `โ
ATF Test execution completed!
|
|
1304
|
+
|
|
1305
|
+
๐งช **Test: ${testName || args.testId}**
|
|
1306
|
+
๐ Execution ID: ${executionId}
|
|
1307
|
+
|
|
1308
|
+
โ ๏ธ Check results using snow_get_atf_results for detailed information.`
|
|
1309
|
+
}]
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
catch (error) {
|
|
1313
|
+
this.logger.error('Failed to execute ATF test:', error);
|
|
1314
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to execute ATF test: ${error}`);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Get ATF Test Results
|
|
1319
|
+
* Queries sys_atf_test_result table
|
|
1320
|
+
*/
|
|
1321
|
+
async getATFResults(args) {
|
|
1322
|
+
try {
|
|
1323
|
+
this.logger.info('Getting ATF test results...');
|
|
1324
|
+
let query = '';
|
|
1325
|
+
if (args.executionId) {
|
|
1326
|
+
query = `sys_id=${args.executionId}`;
|
|
1327
|
+
}
|
|
1328
|
+
else if (args.testId) {
|
|
1329
|
+
// Get latest results for a test
|
|
1330
|
+
query = args.testId.match(/^[a-f0-9]{32}$/) ?
|
|
1331
|
+
`test=${args.testId}` :
|
|
1332
|
+
`test.name=${args.testId}`;
|
|
1333
|
+
}
|
|
1334
|
+
const limit = args.limit || 10;
|
|
1335
|
+
const resultsResponse = await this.client.searchRecords('sys_atf_test_result', query, limit);
|
|
1336
|
+
if (!resultsResponse.success) {
|
|
1337
|
+
throw new Error('Failed to get test results');
|
|
1338
|
+
}
|
|
1339
|
+
const results = resultsResponse.data.result;
|
|
1340
|
+
if (!results.length) {
|
|
1341
|
+
return {
|
|
1342
|
+
content: [{
|
|
1343
|
+
type: 'text',
|
|
1344
|
+
text: 'โ No test results found for the specified criteria.'
|
|
1345
|
+
}]
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
const resultText = results.map((result) => {
|
|
1349
|
+
const status = result.status || 'unknown';
|
|
1350
|
+
const statusEmoji = {
|
|
1351
|
+
'passed': 'โ
',
|
|
1352
|
+
'failed': 'โ',
|
|
1353
|
+
'running': 'โณ',
|
|
1354
|
+
'skipped': 'โญ๏ธ'
|
|
1355
|
+
}[status] || 'โ';
|
|
1356
|
+
return `${statusEmoji} **Test Result**
|
|
1357
|
+
๐ Execution: ${result.sys_id}
|
|
1358
|
+
๐ Status: ${status}
|
|
1359
|
+
โฑ๏ธ Start: ${result.start_time || 'N/A'}
|
|
1360
|
+
โฑ๏ธ End: ${result.end_time || 'Still running'}
|
|
1361
|
+
โฑ๏ธ Duration: ${result.duration || 'N/A'}
|
|
1362
|
+
${result.error_message ? `โ Error: ${result.error_message}` : ''}`;
|
|
1363
|
+
}).join('\n\n');
|
|
1364
|
+
return {
|
|
1365
|
+
content: [{
|
|
1366
|
+
type: 'text',
|
|
1367
|
+
text: `๐ ATF Test Results:
|
|
1368
|
+
|
|
1369
|
+
${resultText}
|
|
1370
|
+
|
|
1371
|
+
โจ Found ${results.length} test result(s)`
|
|
1372
|
+
}]
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
catch (error) {
|
|
1376
|
+
this.logger.error('Failed to get ATF results:', error);
|
|
1377
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to get ATF results: ${error}`);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Create ATF Test Suite
|
|
1382
|
+
* Uses sys_atf_test_suite table
|
|
1383
|
+
*/
|
|
1384
|
+
async createATFTestSuite(args) {
|
|
1385
|
+
try {
|
|
1386
|
+
this.logger.info('Creating ATF test suite...');
|
|
1387
|
+
const suiteData = {
|
|
1388
|
+
name: args.name,
|
|
1389
|
+
description: args.description || '',
|
|
1390
|
+
active: args.active !== false,
|
|
1391
|
+
run_parallel: args.runParallel || false
|
|
1392
|
+
};
|
|
1393
|
+
const updateSetResult = await this.client.ensureUpdateSet();
|
|
1394
|
+
const response = await this.client.createRecord('sys_atf_test_suite', suiteData);
|
|
1395
|
+
if (!response.success) {
|
|
1396
|
+
throw new Error(`Failed to create ATF test suite: ${response.error}`);
|
|
1397
|
+
}
|
|
1398
|
+
const suiteId = response.data.sys_id;
|
|
1399
|
+
// Add tests to suite if provided
|
|
1400
|
+
if (args.tests && args.tests.length > 0) {
|
|
1401
|
+
for (let i = 0; i < args.tests.length; i++) {
|
|
1402
|
+
const testRef = args.tests[i];
|
|
1403
|
+
let testId = testRef;
|
|
1404
|
+
// Resolve test name to ID if needed
|
|
1405
|
+
if (!testRef.match(/^[a-f0-9]{32}$/)) {
|
|
1406
|
+
const testResponse = await this.client.searchRecords('sys_atf_test', `name=${testRef}`, 1);
|
|
1407
|
+
if (testResponse.success && testResponse.data.result.length) {
|
|
1408
|
+
testId = testResponse.data.result[0].sys_id;
|
|
1409
|
+
}
|
|
1410
|
+
else {
|
|
1411
|
+
this.logger.warn(`Test not found: ${testRef}`);
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
// Create suite test relationship
|
|
1416
|
+
const suiteTestData = {
|
|
1417
|
+
test_suite: suiteId,
|
|
1418
|
+
test: testId,
|
|
1419
|
+
order: (i + 1) * 10
|
|
1420
|
+
};
|
|
1421
|
+
await this.client.createRecord('sys_atf_test_suite_test', suiteTestData);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return {
|
|
1425
|
+
content: [{
|
|
1426
|
+
type: 'text',
|
|
1427
|
+
text: `โ
ATF Test Suite created successfully!
|
|
1428
|
+
|
|
1429
|
+
๐ฆ **${args.name}**
|
|
1430
|
+
๐ sys_id: ${suiteId}
|
|
1431
|
+
๐ Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1432
|
+
โก Parallel Execution: ${args.runParallel ? 'Yes' : 'No'}
|
|
1433
|
+
๐ Tests Added: ${args.tests ? args.tests.length : 0}
|
|
1434
|
+
|
|
1435
|
+
๐ Description: ${args.description || 'No description provided'}
|
|
1436
|
+
|
|
1437
|
+
โจ Test suite ready for execution!`
|
|
1438
|
+
}]
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
catch (error) {
|
|
1442
|
+
this.logger.error('Failed to create ATF test suite:', error);
|
|
1443
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to create ATF test suite: ${error}`);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Discover ATF Tests
|
|
1448
|
+
* Searches sys_atf_test and sys_atf_test_suite tables
|
|
1449
|
+
*/
|
|
1450
|
+
async discoverATFTests(args) {
|
|
1451
|
+
try {
|
|
1452
|
+
this.logger.info('Discovering ATF tests...');
|
|
1453
|
+
const type = args.type || 'all';
|
|
1454
|
+
const results = [];
|
|
1455
|
+
// Discover tests
|
|
1456
|
+
if (type === 'test' || type === 'all') {
|
|
1457
|
+
let testQuery = '';
|
|
1458
|
+
if (args.table)
|
|
1459
|
+
testQuery = `table_name=${args.table}`;
|
|
1460
|
+
if (args.active !== undefined) {
|
|
1461
|
+
testQuery += testQuery ? '^' : '';
|
|
1462
|
+
testQuery += `active=${args.active}`;
|
|
1463
|
+
}
|
|
1464
|
+
const testsResponse = await this.client.searchRecords('sys_atf_test', testQuery, 50);
|
|
1465
|
+
if (testsResponse.success) {
|
|
1466
|
+
results.push(...testsResponse.data.result.map((test) => ({
|
|
1467
|
+
type: 'test',
|
|
1468
|
+
name: test.name,
|
|
1469
|
+
sys_id: test.sys_id,
|
|
1470
|
+
description: test.description,
|
|
1471
|
+
active: test.active,
|
|
1472
|
+
table: test.table_name
|
|
1473
|
+
})));
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
// Discover suites
|
|
1477
|
+
if (type === 'suite' || type === 'all') {
|
|
1478
|
+
let suiteQuery = '';
|
|
1479
|
+
if (args.active !== undefined) {
|
|
1480
|
+
suiteQuery = `active=${args.active}`;
|
|
1481
|
+
}
|
|
1482
|
+
const suitesResponse = await this.client.searchRecords('sys_atf_test_suite', suiteQuery, 50);
|
|
1483
|
+
if (suitesResponse.success) {
|
|
1484
|
+
results.push(...suitesResponse.data.result.map((suite) => ({
|
|
1485
|
+
type: 'suite',
|
|
1486
|
+
name: suite.name,
|
|
1487
|
+
sys_id: suite.sys_id,
|
|
1488
|
+
description: suite.description,
|
|
1489
|
+
active: suite.active,
|
|
1490
|
+
run_parallel: suite.run_parallel
|
|
1491
|
+
})));
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
const groupedResults = {
|
|
1495
|
+
tests: results.filter(r => r.type === 'test'),
|
|
1496
|
+
suites: results.filter(r => r.type === 'suite')
|
|
1497
|
+
};
|
|
1498
|
+
return {
|
|
1499
|
+
content: [{
|
|
1500
|
+
type: 'text',
|
|
1501
|
+
text: `๐ Discovered ATF Tests and Suites:
|
|
1502
|
+
|
|
1503
|
+
**Tests (${groupedResults.tests.length}):**
|
|
1504
|
+
${groupedResults.tests.slice(0, 10).map(test => `- ${test.name} ${test.active ? 'โ
' : 'โ'}${test.table ? ` (${test.table})` : ''}
|
|
1505
|
+
${test.description || 'No description'}`).join('\n')}${groupedResults.tests.length > 10 ? '\n ... and more' : ''}
|
|
1506
|
+
|
|
1507
|
+
**Test Suites (${groupedResults.suites.length}):**
|
|
1508
|
+
${groupedResults.suites.slice(0, 10).map(suite => `- ${suite.name} ${suite.active ? 'โ
' : 'โ'}${suite.run_parallel ? ' โก' : ''}
|
|
1509
|
+
${suite.description || 'No description'}`).join('\n')}${groupedResults.suites.length > 10 ? '\n ... and more' : ''}
|
|
1510
|
+
|
|
1511
|
+
โจ Total discovered: ${results.length} items`
|
|
1512
|
+
}]
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
catch (error) {
|
|
1516
|
+
this.logger.error('Failed to discover ATF tests:', error);
|
|
1517
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to discover ATF tests: ${error}`);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Build ATF Step Configuration
|
|
1522
|
+
* Helper to build step config based on type
|
|
1523
|
+
*/
|
|
1524
|
+
buildATFStepConfig(stepType, userConfig) {
|
|
1525
|
+
const baseConfig = {
|
|
1526
|
+
step_type: stepType,
|
|
1527
|
+
...userConfig
|
|
1528
|
+
};
|
|
1529
|
+
// Add type-specific defaults
|
|
1530
|
+
switch (stepType) {
|
|
1531
|
+
case 'form_submission':
|
|
1532
|
+
return {
|
|
1533
|
+
...baseConfig,
|
|
1534
|
+
table: userConfig.table || 'incident',
|
|
1535
|
+
view: userConfig.view || 'default',
|
|
1536
|
+
field_values: userConfig.field_values || {}
|
|
1537
|
+
};
|
|
1538
|
+
case 'impersonate':
|
|
1539
|
+
return {
|
|
1540
|
+
...baseConfig,
|
|
1541
|
+
user: userConfig.user || 'admin'
|
|
1542
|
+
};
|
|
1543
|
+
case 'assert_condition':
|
|
1544
|
+
return {
|
|
1545
|
+
...baseConfig,
|
|
1546
|
+
condition: userConfig.condition || '',
|
|
1547
|
+
expected_value: userConfig.expected_value || true
|
|
1548
|
+
};
|
|
1549
|
+
case 'open_form':
|
|
1550
|
+
return {
|
|
1551
|
+
...baseConfig,
|
|
1552
|
+
table: userConfig.table || 'incident',
|
|
1553
|
+
sys_id: userConfig.sys_id || '',
|
|
1554
|
+
view: userConfig.view || 'default'
|
|
1555
|
+
};
|
|
1556
|
+
case 'server_script':
|
|
1557
|
+
return {
|
|
1558
|
+
...baseConfig,
|
|
1559
|
+
script: userConfig.script || ''
|
|
1560
|
+
};
|
|
1561
|
+
default:
|
|
1562
|
+
return baseConfig;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1042
1565
|
async run() {
|
|
1043
1566
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1044
1567
|
await this.server.connect(transport);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ServiceNow Change Management, Virtual Agent & Performance Analytics MCP Server
|
|
4
|
+
* Handles change requests, chatbot conversations, and performance analytics
|
|
5
|
+
* Uses official ServiceNow REST APIs
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=servicenow-change-virtualagent-pa-mcp.d.ts.map
|