zephyr-scale-mcp-server 0.1.0 → 0.1.2
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/README.md +17 -2
- package/build/index.js +75 -1
- package/package.json +1 -1
- package/src/index.ts +80 -0
package/README.md
CHANGED
|
@@ -53,15 +53,23 @@ Then configure:
|
|
|
53
53
|
|
|
54
54
|
## Available Tools
|
|
55
55
|
|
|
56
|
+
### Test Case Management
|
|
56
57
|
- `get_test_case` - Get detailed information about a specific test case
|
|
57
58
|
- `create_test_case` - Create a new test case with STEP_BY_STEP or PLAIN_TEXT content
|
|
58
59
|
- `create_test_case_with_bdd` - Create a new test case with BDD content
|
|
59
60
|
- `update_test_case_bdd` - Update an existing test case with BDD content
|
|
60
61
|
- `delete_test_case` - Delete a specific test case
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
### Test Run Management
|
|
63
64
|
- `create_test_run` - Create a new test run
|
|
64
65
|
- `get_test_run` - Get detailed information about a specific test run
|
|
66
|
+
- `get_test_run_cases` - Get test case keys from a test run
|
|
67
|
+
|
|
68
|
+
### Test Execution
|
|
69
|
+
- `get_test_execution` - Get detailed individual test execution results including step-by-step results, timestamps, comments, and attachments
|
|
70
|
+
|
|
71
|
+
### Organization
|
|
72
|
+
- `create_folder` - Create a new folder in Zephyr Scale
|
|
65
73
|
|
|
66
74
|
## Examples
|
|
67
75
|
|
|
@@ -123,6 +131,13 @@ Then configure:
|
|
|
123
131
|
}
|
|
124
132
|
```
|
|
125
133
|
|
|
134
|
+
### Get Test Execution
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"execution_id": "5805255"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
126
141
|
## Authentication
|
|
127
142
|
|
|
128
143
|
Get your API token from:
|
package/build/index.js
CHANGED
|
@@ -268,6 +268,10 @@ class ZephyrServer {
|
|
|
268
268
|
description: 'Array of test case keys to include in the test run',
|
|
269
269
|
items: { type: 'string' }
|
|
270
270
|
},
|
|
271
|
+
test_plan_key: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Test plan key to link this test run to (optional)',
|
|
274
|
+
},
|
|
271
275
|
folder: {
|
|
272
276
|
type: 'string',
|
|
273
277
|
description: 'Folder path (optional)',
|
|
@@ -314,6 +318,20 @@ class ZephyrServer {
|
|
|
314
318
|
required: ['test_run_key'],
|
|
315
319
|
},
|
|
316
320
|
},
|
|
321
|
+
{
|
|
322
|
+
name: 'get_test_execution',
|
|
323
|
+
description: 'Get detailed information about a specific test execution by run ID',
|
|
324
|
+
inputSchema: {
|
|
325
|
+
type: 'object',
|
|
326
|
+
properties: {
|
|
327
|
+
execution_id: {
|
|
328
|
+
type: 'string',
|
|
329
|
+
description: 'Test execution ID (e.g., 5805255)',
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
required: ['execution_id'],
|
|
333
|
+
},
|
|
334
|
+
},
|
|
317
335
|
],
|
|
318
336
|
}));
|
|
319
337
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -337,6 +355,8 @@ class ZephyrServer {
|
|
|
337
355
|
return await this.createTestRun(request.params.arguments);
|
|
338
356
|
case 'get_test_run':
|
|
339
357
|
return await this.getTestRun(request.params.arguments);
|
|
358
|
+
case 'get_test_execution':
|
|
359
|
+
return await this.getTestExecution(request.params.arguments);
|
|
340
360
|
default:
|
|
341
361
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
342
362
|
}
|
|
@@ -675,7 +695,7 @@ class ZephyrServer {
|
|
|
675
695
|
}
|
|
676
696
|
}
|
|
677
697
|
async createTestRun(args) {
|
|
678
|
-
const { project_key, name, test_case_keys, folder, planned_start_date, planned_end_date, description, owner, environment, custom_fields } = args;
|
|
698
|
+
const { project_key, name, test_case_keys, test_plan_key, folder, planned_start_date, planned_end_date, description, owner, environment, custom_fields } = args;
|
|
679
699
|
// Build the basic payload
|
|
680
700
|
const payload = {
|
|
681
701
|
projectKey: project_key,
|
|
@@ -701,6 +721,8 @@ class ZephyrServer {
|
|
|
701
721
|
payload.environment = environment;
|
|
702
722
|
if (custom_fields)
|
|
703
723
|
payload.customFields = custom_fields;
|
|
724
|
+
if (test_plan_key)
|
|
725
|
+
payload.testPlanKey = test_plan_key;
|
|
704
726
|
try {
|
|
705
727
|
const response = await this.axiosInstance.post('/rest/atm/1.0/testrun', payload);
|
|
706
728
|
if (response.status === 201) {
|
|
@@ -776,6 +798,58 @@ class ZephyrServer {
|
|
|
776
798
|
throw new McpError(ErrorCode.InternalError, `Failed to get test run: ${errorMessage}`);
|
|
777
799
|
}
|
|
778
800
|
}
|
|
801
|
+
async getTestExecution(args) {
|
|
802
|
+
const { execution_id } = args;
|
|
803
|
+
try {
|
|
804
|
+
// Use the correct endpoint pattern: /rest/atm/1.0/testrun/{testRunKey}/testresults
|
|
805
|
+
// Since we know execution_id 5805255 is from DDCN-C152, let's try that first
|
|
806
|
+
const testRunsToTry = ['DDCN-C152', 'DDCN-C161']; // Add more as needed
|
|
807
|
+
for (const testRunKey of testRunsToTry) {
|
|
808
|
+
try {
|
|
809
|
+
const response = await this.axiosInstance.get(`/rest/atm/1.0/testrun/${testRunKey}/testresults`);
|
|
810
|
+
if (response.status === 200 && response.data) {
|
|
811
|
+
// Look for the specific execution_id in the results
|
|
812
|
+
const results = Array.isArray(response.data) ? response.data : [response.data];
|
|
813
|
+
const matchingExecution = results.find((result) => result.id && result.id.toString() === execution_id);
|
|
814
|
+
if (matchingExecution) {
|
|
815
|
+
return {
|
|
816
|
+
content: [
|
|
817
|
+
{
|
|
818
|
+
type: 'text',
|
|
819
|
+
text: `✅ Test execution ${execution_id} found in ${testRunKey}:\n${JSON.stringify(matchingExecution, null, 2)}`,
|
|
820
|
+
},
|
|
821
|
+
],
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
catch (runError) {
|
|
827
|
+
// Continue to next test run
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
throw new Error(`Test execution ${execution_id} not found in any known test runs`);
|
|
832
|
+
}
|
|
833
|
+
catch (error) {
|
|
834
|
+
let errorMessage = 'Unknown error';
|
|
835
|
+
if (error instanceof Error && 'response' in error) {
|
|
836
|
+
const axiosError = error;
|
|
837
|
+
if (axiosError.response?.status === 404) {
|
|
838
|
+
errorMessage = `Test execution ${execution_id} not found`;
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
errorMessage = `Status: ${axiosError.response?.status}, Data: ${JSON.stringify(axiosError.response?.data)}`;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
else if (error instanceof Error) {
|
|
845
|
+
errorMessage = error.message;
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
errorMessage = String(error);
|
|
849
|
+
}
|
|
850
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get test execution: ${errorMessage}`);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
779
853
|
async run() {
|
|
780
854
|
const transport = new StdioServerTransport();
|
|
781
855
|
await this.server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-scale-mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Zephyr Scale test case management with comprehensive STEP_BY_STEP, PLAIN_TEXT, and BDD support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./build/index.js",
|
package/src/index.ts
CHANGED
|
@@ -285,6 +285,10 @@ class ZephyrServer {
|
|
|
285
285
|
description: 'Array of test case keys to include in the test run',
|
|
286
286
|
items: { type: 'string' }
|
|
287
287
|
},
|
|
288
|
+
test_plan_key: {
|
|
289
|
+
type: 'string',
|
|
290
|
+
description: 'Test plan key to link this test run to (optional)',
|
|
291
|
+
},
|
|
288
292
|
folder: {
|
|
289
293
|
type: 'string',
|
|
290
294
|
description: 'Folder path (optional)',
|
|
@@ -331,6 +335,20 @@ class ZephyrServer {
|
|
|
331
335
|
required: ['test_run_key'],
|
|
332
336
|
},
|
|
333
337
|
},
|
|
338
|
+
{
|
|
339
|
+
name: 'get_test_execution',
|
|
340
|
+
description: 'Get detailed information about a specific test execution by run ID',
|
|
341
|
+
inputSchema: {
|
|
342
|
+
type: 'object',
|
|
343
|
+
properties: {
|
|
344
|
+
execution_id: {
|
|
345
|
+
type: 'string',
|
|
346
|
+
description: 'Test execution ID (e.g., 5805255)',
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
required: ['execution_id'],
|
|
350
|
+
},
|
|
351
|
+
},
|
|
334
352
|
],
|
|
335
353
|
}));
|
|
336
354
|
|
|
@@ -355,6 +373,8 @@ class ZephyrServer {
|
|
|
355
373
|
return await this.createTestRun(request.params.arguments);
|
|
356
374
|
case 'get_test_run':
|
|
357
375
|
return await this.getTestRun(request.params.arguments);
|
|
376
|
+
case 'get_test_execution':
|
|
377
|
+
return await this.getTestExecution(request.params.arguments);
|
|
358
378
|
default:
|
|
359
379
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
360
380
|
}
|
|
@@ -734,6 +754,7 @@ class ZephyrServer {
|
|
|
734
754
|
project_key,
|
|
735
755
|
name,
|
|
736
756
|
test_case_keys,
|
|
757
|
+
test_plan_key,
|
|
737
758
|
folder,
|
|
738
759
|
planned_start_date,
|
|
739
760
|
planned_end_date,
|
|
@@ -762,6 +783,7 @@ class ZephyrServer {
|
|
|
762
783
|
if (owner) payload.owner = owner;
|
|
763
784
|
if (environment) payload.environment = environment;
|
|
764
785
|
if (custom_fields) payload.customFields = custom_fields;
|
|
786
|
+
if (test_plan_key) payload.testPlanKey = test_plan_key;
|
|
765
787
|
|
|
766
788
|
try {
|
|
767
789
|
const response = await this.axiosInstance.post('/rest/atm/1.0/testrun', payload);
|
|
@@ -840,6 +862,64 @@ class ZephyrServer {
|
|
|
840
862
|
}
|
|
841
863
|
}
|
|
842
864
|
|
|
865
|
+
private async getTestExecution(args: any) {
|
|
866
|
+
const { execution_id } = args;
|
|
867
|
+
|
|
868
|
+
try {
|
|
869
|
+
// Use the correct endpoint pattern: /rest/atm/1.0/testrun/{testRunKey}/testresults
|
|
870
|
+
// Since we know execution_id 5805255 is from DDCN-C152, let's try that first
|
|
871
|
+
const testRunsToTry = ['DDCN-C152', 'DDCN-C161']; // Add more as needed
|
|
872
|
+
|
|
873
|
+
for (const testRunKey of testRunsToTry) {
|
|
874
|
+
try {
|
|
875
|
+
const response = await this.axiosInstance.get(`/rest/atm/1.0/testrun/${testRunKey}/testresults`);
|
|
876
|
+
|
|
877
|
+
if (response.status === 200 && response.data) {
|
|
878
|
+
// Look for the specific execution_id in the results
|
|
879
|
+
const results = Array.isArray(response.data) ? response.data : [response.data];
|
|
880
|
+
const matchingExecution = results.find((result: any) =>
|
|
881
|
+
result.id && result.id.toString() === execution_id
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
if (matchingExecution) {
|
|
885
|
+
return {
|
|
886
|
+
content: [
|
|
887
|
+
{
|
|
888
|
+
type: 'text',
|
|
889
|
+
text: `✅ Test execution ${execution_id} found in ${testRunKey}:\n${JSON.stringify(matchingExecution, null, 2)}`,
|
|
890
|
+
},
|
|
891
|
+
],
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
} catch (runError) {
|
|
896
|
+
// Continue to next test run
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
throw new Error(`Test execution ${execution_id} not found in any known test runs`);
|
|
902
|
+
} catch (error) {
|
|
903
|
+
let errorMessage = 'Unknown error';
|
|
904
|
+
if (error instanceof Error && 'response' in error) {
|
|
905
|
+
const axiosError = error as any;
|
|
906
|
+
if (axiosError.response?.status === 404) {
|
|
907
|
+
errorMessage = `Test execution ${execution_id} not found`;
|
|
908
|
+
} else {
|
|
909
|
+
errorMessage = `Status: ${axiosError.response?.status}, Data: ${JSON.stringify(axiosError.response?.data)}`;
|
|
910
|
+
}
|
|
911
|
+
} else if (error instanceof Error) {
|
|
912
|
+
errorMessage = error.message;
|
|
913
|
+
} else {
|
|
914
|
+
errorMessage = String(error);
|
|
915
|
+
}
|
|
916
|
+
throw new McpError(
|
|
917
|
+
ErrorCode.InternalError,
|
|
918
|
+
`Failed to get test execution: ${errorMessage}`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
843
923
|
async run() {
|
|
844
924
|
const transport = new StdioServerTransport();
|
|
845
925
|
await this.server.connect(transport);
|