zephyr-scale-mcp-server 0.5.0 → 0.5.1
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/build/index.js +2 -0
- package/build/tool-handlers.js +73 -0
- package/build/tool-schemas.js +23 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/tool-handlers.ts +84 -0
- package/src/tool-schemas.ts +23 -0
- package/src/types.ts +6 -0
package/build/index.js
CHANGED
|
@@ -69,6 +69,8 @@ class ZephyrServer {
|
|
|
69
69
|
return await this.toolHandlers.searchTestRuns(args);
|
|
70
70
|
case 'add_test_cases_to_run':
|
|
71
71
|
return await this.toolHandlers.addTestCasesToRun(args);
|
|
72
|
+
case 'list_executions_by_cycle':
|
|
73
|
+
return await this.toolHandlers.listExecutionsByCycle(args);
|
|
72
74
|
default:
|
|
73
75
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
74
76
|
}
|
package/build/tool-handlers.js
CHANGED
|
@@ -911,6 +911,79 @@ export class ZephyrToolHandlers {
|
|
|
911
911
|
throw new McpError(ErrorCode.InternalError, `Failed to add test cases: ${this.formatError(error)}`);
|
|
912
912
|
}
|
|
913
913
|
}
|
|
914
|
+
async listExecutionsByCycle(args) {
|
|
915
|
+
const { test_cycle_key, project_key, max_results = 100 } = args;
|
|
916
|
+
if (this.jiraConfig.type === 'cloud') {
|
|
917
|
+
try {
|
|
918
|
+
// Cloud v2: GET /testexecutions?projectKey=X&testCycle=Y
|
|
919
|
+
const params = {
|
|
920
|
+
projectKey: project_key,
|
|
921
|
+
testCycle: test_cycle_key,
|
|
922
|
+
maxResults: max_results,
|
|
923
|
+
};
|
|
924
|
+
const response = await this.axiosInstance.get('/testexecutions', { params });
|
|
925
|
+
const executions = Array.isArray(response.data)
|
|
926
|
+
? response.data
|
|
927
|
+
: response.data?.values ?? [];
|
|
928
|
+
const summary = executions.map((ex) => ({
|
|
929
|
+
key: ex.key,
|
|
930
|
+
testCaseKey: ex.testCase?.self?.match(/testcases\/(.+?)\/versions/)?.[1] || ex.testCase?.id,
|
|
931
|
+
status: ex.testExecutionStatus?.id,
|
|
932
|
+
statusName: ex.testExecutionStatus?.name,
|
|
933
|
+
executedById: ex.executedById,
|
|
934
|
+
assignedToId: ex.assignedToId,
|
|
935
|
+
actualEndDate: ex.actualEndDate,
|
|
936
|
+
automated: ex.automated,
|
|
937
|
+
comment: ex.comment,
|
|
938
|
+
}));
|
|
939
|
+
// Count statuses
|
|
940
|
+
const statusCounts = {};
|
|
941
|
+
for (const ex of executions) {
|
|
942
|
+
const statusId = ex.testExecutionStatus?.id?.toString() || 'unknown';
|
|
943
|
+
statusCounts[statusId] = (statusCounts[statusId] || 0) + 1;
|
|
944
|
+
}
|
|
945
|
+
return {
|
|
946
|
+
content: [{
|
|
947
|
+
type: 'text',
|
|
948
|
+
text: `✅ Found ${executions.length} execution(s) for cycle ${test_cycle_key}:\n${JSON.stringify({
|
|
949
|
+
cycleKey: test_cycle_key,
|
|
950
|
+
totalExecutions: executions.length,
|
|
951
|
+
statusCounts,
|
|
952
|
+
executions: summary,
|
|
953
|
+
}, null, 2)}`,
|
|
954
|
+
}],
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
catch (error) {
|
|
958
|
+
throw new McpError(ErrorCode.InternalError, `Failed to list executions: ${this.formatError(error)}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
// Data Center: GET /rest/atm/1.0/testrun/{key}/testresults
|
|
962
|
+
try {
|
|
963
|
+
const response = await this.axiosInstance.get(`${this.jiraConfig.apiEndpoints.testrun}/${test_cycle_key}/testresults`);
|
|
964
|
+
const results = Array.isArray(response.data) ? response.data : [];
|
|
965
|
+
return {
|
|
966
|
+
content: [{
|
|
967
|
+
type: 'text',
|
|
968
|
+
text: `✅ Found ${results.length} execution(s) for cycle ${test_cycle_key}:\n${JSON.stringify({
|
|
969
|
+
cycleKey: test_cycle_key,
|
|
970
|
+
totalExecutions: results.length,
|
|
971
|
+
executions: results.map((r) => ({
|
|
972
|
+
id: r.id,
|
|
973
|
+
testCaseKey: r.testCaseKey,
|
|
974
|
+
status: r.status,
|
|
975
|
+
executedBy: r.executedBy,
|
|
976
|
+
executionDate: r.executionDate,
|
|
977
|
+
automated: r.automated,
|
|
978
|
+
})),
|
|
979
|
+
}, null, 2)}`,
|
|
980
|
+
}],
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
catch (error) {
|
|
984
|
+
throw new McpError(ErrorCode.InternalError, `Failed to list executions: ${this.formatError(error)}`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
914
987
|
async resolveJiraIssueId(issueKey) {
|
|
915
988
|
// The Zephyr API key is NOT valid for the Jira REST API — Jira Cloud requires
|
|
916
989
|
// Basic Auth: base64(email:api_token) via JIRA_USERNAME + JIRA_API_TOKEN env vars.
|
package/build/tool-schemas.js
CHANGED
|
@@ -379,6 +379,29 @@ export const toolSchemas = [
|
|
|
379
379
|
},
|
|
380
380
|
},
|
|
381
381
|
},
|
|
382
|
+
{
|
|
383
|
+
name: 'list_executions_by_cycle',
|
|
384
|
+
description: 'List all test executions for a specific test cycle. Returns execution status, executedBy, actualEndDate for each test case in the cycle. Cloud only.',
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: 'object',
|
|
387
|
+
properties: {
|
|
388
|
+
test_cycle_key: {
|
|
389
|
+
type: 'string',
|
|
390
|
+
description: 'Test cycle key (e.g., DDCN-R371)',
|
|
391
|
+
},
|
|
392
|
+
project_key: {
|
|
393
|
+
type: 'string',
|
|
394
|
+
description: 'Project key (required for Cloud)',
|
|
395
|
+
},
|
|
396
|
+
max_results: {
|
|
397
|
+
type: 'number',
|
|
398
|
+
description: 'Maximum number of results to return (optional, default 100)',
|
|
399
|
+
default: 100,
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
required: ['test_cycle_key', 'project_key'],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
382
405
|
{
|
|
383
406
|
name: 'delete_test_run',
|
|
384
407
|
description: 'Delete a specific test run (Data Center only — not supported on Cloud v2)',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-scale-mcp-server",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
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
|
@@ -89,6 +89,8 @@ class ZephyrServer {
|
|
|
89
89
|
return await this.toolHandlers.searchTestRuns(args as any);
|
|
90
90
|
case 'add_test_cases_to_run':
|
|
91
91
|
return await this.toolHandlers.addTestCasesToRun(args as any);
|
|
92
|
+
case 'list_executions_by_cycle':
|
|
93
|
+
return await this.toolHandlers.listExecutionsByCycle(args as any);
|
|
92
94
|
default:
|
|
93
95
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
94
96
|
}
|
package/src/tool-handlers.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
AddTestCasesToRunArgs,
|
|
11
11
|
SearchTestRunsArgs,
|
|
12
12
|
GetTestExecutionArgs,
|
|
13
|
+
ListExecutionsByCycleArgs,
|
|
13
14
|
JiraConfig
|
|
14
15
|
} from './types.js';
|
|
15
16
|
import { convertToGherkin, resolveFolderIdByPath } from './utils.js';
|
|
@@ -992,6 +993,89 @@ export class ZephyrToolHandlers {
|
|
|
992
993
|
}
|
|
993
994
|
}
|
|
994
995
|
|
|
996
|
+
async listExecutionsByCycle(args: ListExecutionsByCycleArgs) {
|
|
997
|
+
const { test_cycle_key, project_key, max_results = 100 } = args;
|
|
998
|
+
|
|
999
|
+
if (this.jiraConfig.type === 'cloud') {
|
|
1000
|
+
try {
|
|
1001
|
+
// Cloud v2: GET /testexecutions?projectKey=X&testCycle=Y
|
|
1002
|
+
const params: Record<string, any> = {
|
|
1003
|
+
projectKey: project_key,
|
|
1004
|
+
testCycle: test_cycle_key,
|
|
1005
|
+
maxResults: max_results,
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
const response = await this.axiosInstance.get('/testexecutions', { params });
|
|
1009
|
+
|
|
1010
|
+
const executions = Array.isArray(response.data)
|
|
1011
|
+
? response.data
|
|
1012
|
+
: response.data?.values ?? [];
|
|
1013
|
+
|
|
1014
|
+
const summary = executions.map((ex: any) => ({
|
|
1015
|
+
key: ex.key,
|
|
1016
|
+
testCaseKey: ex.testCase?.self?.match(/testcases\/(.+?)\/versions/)?.[1] || ex.testCase?.id,
|
|
1017
|
+
status: ex.testExecutionStatus?.id,
|
|
1018
|
+
statusName: ex.testExecutionStatus?.name,
|
|
1019
|
+
executedById: ex.executedById,
|
|
1020
|
+
assignedToId: ex.assignedToId,
|
|
1021
|
+
actualEndDate: ex.actualEndDate,
|
|
1022
|
+
automated: ex.automated,
|
|
1023
|
+
comment: ex.comment,
|
|
1024
|
+
}));
|
|
1025
|
+
|
|
1026
|
+
// Count statuses
|
|
1027
|
+
const statusCounts: Record<string, number> = {};
|
|
1028
|
+
for (const ex of executions) {
|
|
1029
|
+
const statusId = ex.testExecutionStatus?.id?.toString() || 'unknown';
|
|
1030
|
+
statusCounts[statusId] = (statusCounts[statusId] || 0) + 1;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
return {
|
|
1034
|
+
content: [{
|
|
1035
|
+
type: 'text',
|
|
1036
|
+
text: `✅ Found ${executions.length} execution(s) for cycle ${test_cycle_key}:\n${JSON.stringify({
|
|
1037
|
+
cycleKey: test_cycle_key,
|
|
1038
|
+
totalExecutions: executions.length,
|
|
1039
|
+
statusCounts,
|
|
1040
|
+
executions: summary,
|
|
1041
|
+
}, null, 2)}`,
|
|
1042
|
+
}],
|
|
1043
|
+
};
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
throw new McpError(ErrorCode.InternalError, `Failed to list executions: ${this.formatError(error)}`);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Data Center: GET /rest/atm/1.0/testrun/{key}/testresults
|
|
1050
|
+
try {
|
|
1051
|
+
const response = await this.axiosInstance.get(
|
|
1052
|
+
`${this.jiraConfig.apiEndpoints.testrun}/${test_cycle_key}/testresults`
|
|
1053
|
+
);
|
|
1054
|
+
|
|
1055
|
+
const results = Array.isArray(response.data) ? response.data : [];
|
|
1056
|
+
|
|
1057
|
+
return {
|
|
1058
|
+
content: [{
|
|
1059
|
+
type: 'text',
|
|
1060
|
+
text: `✅ Found ${results.length} execution(s) for cycle ${test_cycle_key}:\n${JSON.stringify({
|
|
1061
|
+
cycleKey: test_cycle_key,
|
|
1062
|
+
totalExecutions: results.length,
|
|
1063
|
+
executions: results.map((r: any) => ({
|
|
1064
|
+
id: r.id,
|
|
1065
|
+
testCaseKey: r.testCaseKey,
|
|
1066
|
+
status: r.status,
|
|
1067
|
+
executedBy: r.executedBy,
|
|
1068
|
+
executionDate: r.executionDate,
|
|
1069
|
+
automated: r.automated,
|
|
1070
|
+
})),
|
|
1071
|
+
}, null, 2)}`,
|
|
1072
|
+
}],
|
|
1073
|
+
};
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
throw new McpError(ErrorCode.InternalError, `Failed to list executions: ${this.formatError(error)}`);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
995
1079
|
private async resolveJiraIssueId(issueKey: string): Promise<number> {
|
|
996
1080
|
// The Zephyr API key is NOT valid for the Jira REST API — Jira Cloud requires
|
|
997
1081
|
// Basic Auth: base64(email:api_token) via JIRA_USERNAME + JIRA_API_TOKEN env vars.
|
package/src/tool-schemas.ts
CHANGED
|
@@ -379,6 +379,29 @@ export const toolSchemas = [
|
|
|
379
379
|
},
|
|
380
380
|
},
|
|
381
381
|
},
|
|
382
|
+
{
|
|
383
|
+
name: 'list_executions_by_cycle',
|
|
384
|
+
description: 'List all test executions for a specific test cycle. Returns execution status, executedBy, actualEndDate for each test case in the cycle. Cloud only.',
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: 'object',
|
|
387
|
+
properties: {
|
|
388
|
+
test_cycle_key: {
|
|
389
|
+
type: 'string',
|
|
390
|
+
description: 'Test cycle key (e.g., DDCN-R371)',
|
|
391
|
+
},
|
|
392
|
+
project_key: {
|
|
393
|
+
type: 'string',
|
|
394
|
+
description: 'Project key (required for Cloud)',
|
|
395
|
+
},
|
|
396
|
+
max_results: {
|
|
397
|
+
type: 'number',
|
|
398
|
+
description: 'Maximum number of results to return (optional, default 100)',
|
|
399
|
+
default: 100,
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
required: ['test_cycle_key', 'project_key'],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
382
405
|
{
|
|
383
406
|
name: 'delete_test_run',
|
|
384
407
|
description: 'Delete a specific test run (Data Center only — not supported on Cloud v2)',
|
package/src/types.ts
CHANGED
|
@@ -96,6 +96,12 @@ export interface SearchTestRunsArgs {
|
|
|
96
96
|
fields?: string;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
export interface ListExecutionsByCycleArgs {
|
|
100
|
+
test_cycle_key: string;
|
|
101
|
+
project_key: string;
|
|
102
|
+
max_results?: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
99
105
|
export type JiraType = 'cloud' | 'datacenter';
|
|
100
106
|
|
|
101
107
|
export interface ApiEndpoints {
|