zephyr-scale-mcp-server 0.4.1 → 0.4.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/build/tool-handlers.js +31 -2
- package/build/tool-schemas.js +1 -1
- package/build/utils.js +1 -0
- package/package.json +1 -1
- package/src/tool-handlers.ts +36 -2
- package/src/tool-schemas.ts +1 -1
- package/src/types.ts +1 -0
- package/src/utils.ts +1 -0
package/build/tool-handlers.js
CHANGED
|
@@ -34,7 +34,7 @@ export class ZephyrToolHandlers {
|
|
|
34
34
|
return this.createTestCaseDC(args);
|
|
35
35
|
}
|
|
36
36
|
async createTestCaseCloud(args) {
|
|
37
|
-
const { project_key, name, test_script, folder, priority, precondition, objective, estimated_time, labels, custom_fields, } = args;
|
|
37
|
+
const { project_key, name, test_script, folder, priority, precondition, objective, estimated_time, labels, custom_fields, issue_links, } = args;
|
|
38
38
|
const payload = { projectKey: project_key, name };
|
|
39
39
|
// Cloud v2 uses statusName/priorityName (strings), folderId (integer)
|
|
40
40
|
payload.statusName = 'Draft';
|
|
@@ -66,10 +66,27 @@ export class ZephyrToolHandlers {
|
|
|
66
66
|
if (test_script) {
|
|
67
67
|
await this.upsertTestScriptCloud(testKey, test_script);
|
|
68
68
|
}
|
|
69
|
+
// Step 3: link Jira issues via POST /testcases/{key}/links/issues
|
|
70
|
+
// IssueLinkInput requires a numeric issueId — resolve each key via Jira REST API
|
|
71
|
+
const linkWarnings = [];
|
|
72
|
+
if (issue_links && issue_links.length > 0) {
|
|
73
|
+
for (const issueKey of issue_links) {
|
|
74
|
+
try {
|
|
75
|
+
const issueId = await this.resolveJiraIssueId(issueKey);
|
|
76
|
+
await this.axiosInstance.post(`${this.jiraConfig.apiEndpoints.testcase}/${testKey}/links/issues`, { issueId });
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
linkWarnings.push(`${issueKey}: ${this.formatError(e)}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const warningText = linkWarnings.length > 0
|
|
84
|
+
? `\n⚠️ Some issue links failed:\n${linkWarnings.map(w => ` - ${w}`).join('\n')}`
|
|
85
|
+
: '';
|
|
69
86
|
return {
|
|
70
87
|
content: [{
|
|
71
88
|
type: 'text',
|
|
72
|
-
text: `✅ Test case created successfully: ${testKey}\n${JSON.stringify({ key: testKey, type: test_script?.type || 'none' }, null, 2)}`,
|
|
89
|
+
text: `✅ Test case created successfully: ${testKey}\n${JSON.stringify({ key: testKey, type: test_script?.type || 'none', linkedIssues: (issue_links ?? []).length - linkWarnings.length }, null, 2)}${warningText}`,
|
|
73
90
|
}],
|
|
74
91
|
};
|
|
75
92
|
}
|
|
@@ -751,6 +768,18 @@ export class ZephyrToolHandlers {
|
|
|
751
768
|
throw new McpError(ErrorCode.InternalError, `Failed to add test cases: ${this.formatError(error)}`);
|
|
752
769
|
}
|
|
753
770
|
}
|
|
771
|
+
async resolveJiraIssueId(issueKey) {
|
|
772
|
+
// The Zephyr API key is a Jira-issued token — it works against the Jira REST API too.
|
|
773
|
+
// We call GET {jiraBaseUrl}/rest/api/3/issue/{key}?fields=id to get the numeric issue ID
|
|
774
|
+
// required by POST /testcases/{key}/links/issues { issueId: <integer> }.
|
|
775
|
+
const url = `${this.jiraConfig.jiraBaseUrl}/rest/api/3/issue/${issueKey}?fields=id`;
|
|
776
|
+
const response = await this.axiosInstance.get(url, { baseURL: '' });
|
|
777
|
+
const id = parseInt(response.data.id, 10);
|
|
778
|
+
if (!id || isNaN(id)) {
|
|
779
|
+
throw new Error(`Could not resolve numeric ID for Jira issue "${issueKey}"`);
|
|
780
|
+
}
|
|
781
|
+
return id;
|
|
782
|
+
}
|
|
754
783
|
formatError(error) {
|
|
755
784
|
if (error instanceof Error && 'response' in error) {
|
|
756
785
|
const axiosError = error;
|
package/build/tool-schemas.js
CHANGED
|
@@ -110,7 +110,7 @@ export const toolSchemas = [
|
|
|
110
110
|
},
|
|
111
111
|
issue_links: {
|
|
112
112
|
type: 'array',
|
|
113
|
-
description: 'Array of issue
|
|
113
|
+
description: 'Array of Jira issue keys to link to this test case (e.g. ["PROJ-123", "PROJ-456"]). On Cloud, each key is resolved to a numeric Jira issue ID via the Jira REST API, then linked via POST /testcases/{key}/links/issues — failures are reported as warnings but do not fail the tool call. On Data Center, sent directly in the create payload.',
|
|
114
114
|
items: { type: 'string' }
|
|
115
115
|
},
|
|
116
116
|
custom_fields: {
|
package/build/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-scale-mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.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/tool-handlers.ts
CHANGED
|
@@ -46,7 +46,7 @@ export class ZephyrToolHandlers {
|
|
|
46
46
|
private async createTestCaseCloud(args: TestCaseArgs) {
|
|
47
47
|
const {
|
|
48
48
|
project_key, name, test_script, folder, priority, precondition,
|
|
49
|
-
objective, estimated_time, labels, custom_fields,
|
|
49
|
+
objective, estimated_time, labels, custom_fields, issue_links,
|
|
50
50
|
} = args;
|
|
51
51
|
|
|
52
52
|
const payload: any = { projectKey: project_key, name };
|
|
@@ -79,10 +79,31 @@ export class ZephyrToolHandlers {
|
|
|
79
79
|
await this.upsertTestScriptCloud(testKey, test_script);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Step 3: link Jira issues via POST /testcases/{key}/links/issues
|
|
83
|
+
// IssueLinkInput requires a numeric issueId — resolve each key via Jira REST API
|
|
84
|
+
const linkWarnings: string[] = [];
|
|
85
|
+
if (issue_links && issue_links.length > 0) {
|
|
86
|
+
for (const issueKey of issue_links) {
|
|
87
|
+
try {
|
|
88
|
+
const issueId = await this.resolveJiraIssueId(issueKey);
|
|
89
|
+
await this.axiosInstance.post(
|
|
90
|
+
`${this.jiraConfig.apiEndpoints.testcase}/${testKey}/links/issues`,
|
|
91
|
+
{ issueId }
|
|
92
|
+
);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
linkWarnings.push(`${issueKey}: ${this.formatError(e)}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const warningText = linkWarnings.length > 0
|
|
100
|
+
? `\n⚠️ Some issue links failed:\n${linkWarnings.map(w => ` - ${w}`).join('\n')}`
|
|
101
|
+
: '';
|
|
102
|
+
|
|
82
103
|
return {
|
|
83
104
|
content: [{
|
|
84
105
|
type: 'text',
|
|
85
|
-
text: `✅ Test case created successfully: ${testKey}\n${JSON.stringify({ key: testKey, type: test_script?.type || 'none' }, null, 2)}`,
|
|
106
|
+
text: `✅ Test case created successfully: ${testKey}\n${JSON.stringify({ key: testKey, type: test_script?.type || 'none', linkedIssues: (issue_links ?? []).length - linkWarnings.length }, null, 2)}${warningText}`,
|
|
86
107
|
}],
|
|
87
108
|
};
|
|
88
109
|
} catch (error) {
|
|
@@ -824,6 +845,19 @@ export class ZephyrToolHandlers {
|
|
|
824
845
|
}
|
|
825
846
|
}
|
|
826
847
|
|
|
848
|
+
private async resolveJiraIssueId(issueKey: string): Promise<number> {
|
|
849
|
+
// The Zephyr API key is a Jira-issued token — it works against the Jira REST API too.
|
|
850
|
+
// We call GET {jiraBaseUrl}/rest/api/3/issue/{key}?fields=id to get the numeric issue ID
|
|
851
|
+
// required by POST /testcases/{key}/links/issues { issueId: <integer> }.
|
|
852
|
+
const url = `${this.jiraConfig.jiraBaseUrl}/rest/api/3/issue/${issueKey}?fields=id`;
|
|
853
|
+
const response = await this.axiosInstance.get(url, { baseURL: '' });
|
|
854
|
+
const id = parseInt(response.data.id, 10);
|
|
855
|
+
if (!id || isNaN(id)) {
|
|
856
|
+
throw new Error(`Could not resolve numeric ID for Jira issue "${issueKey}"`);
|
|
857
|
+
}
|
|
858
|
+
return id;
|
|
859
|
+
}
|
|
860
|
+
|
|
827
861
|
private formatError(error: unknown): string {
|
|
828
862
|
if (error instanceof Error && 'response' in error) {
|
|
829
863
|
const axiosError = error as any;
|
package/src/tool-schemas.ts
CHANGED
|
@@ -110,7 +110,7 @@ export const toolSchemas = [
|
|
|
110
110
|
},
|
|
111
111
|
issue_links: {
|
|
112
112
|
type: 'array',
|
|
113
|
-
description: 'Array of issue
|
|
113
|
+
description: 'Array of Jira issue keys to link to this test case (e.g. ["PROJ-123", "PROJ-456"]). On Cloud, each key is resolved to a numeric Jira issue ID via the Jira REST API, then linked via POST /testcases/{key}/links/issues — failures are reported as warnings but do not fail the tool call. On Data Center, sent directly in the create payload.',
|
|
114
114
|
items: { type: 'string' }
|
|
115
115
|
},
|
|
116
116
|
custom_fields: {
|
package/src/types.ts
CHANGED