@smartbear/mcp 0.26.0 → 0.27.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/README.md +10 -2
- package/dist/package.json.js +1 -1
- package/dist/qmetry/client/api/client-api.js +13 -1
- package/dist/qmetry/client/auto-resolve.js +23 -1
- package/dist/qmetry/client/handlers.js +10 -2
- package/dist/qmetry/client/issues.js +113 -1
- package/dist/qmetry/client/testcase.js +82 -1
- package/dist/qmetry/client/testsuite.js +20 -8
- package/dist/qmetry/client/tools/index.js +5 -2
- package/dist/qmetry/client/tools/issue-tools.js +163 -1
- package/dist/qmetry/client/tools/testcase-tools.js +81 -7
- package/dist/qmetry/client/tools/testsuite-tools.js +291 -26
- package/dist/qmetry/client/tools/udf-tools.js +294 -0
- package/dist/qmetry/client/udf.js +376 -0
- package/dist/qmetry/client.js +30 -3
- package/dist/qmetry/config/constants.js +63 -2
- package/dist/qmetry/config/rest-endpoints.js +7 -1
- package/dist/qmetry/types/common.js +85 -47
- package/dist/qmetry/types/issues.js +5 -0
- package/dist/qmetry/types/udf.js +77 -0
- package/dist/swagger/client/api.js +421 -8
- package/dist/swagger/client/configuration.js +9 -0
- package/dist/swagger/client/functional-testing-api.js +38 -2
- package/dist/swagger/client/functional-testing-tools.js +18 -0
- package/dist/swagger/client/functional-testing-types.js +11 -0
- package/dist/swagger/client/portal-types.js +35 -3
- package/dist/swagger/client/portal-utils.js +50 -0
- package/dist/swagger/client/registry-types.js +8 -0
- package/dist/swagger/client/tools.js +25 -4
- package/dist/swagger/client/utils.js +37 -0
- package/dist/swagger/client.js +37 -5
- package/package.json +1 -1
package/dist/qmetry/client.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import zod__default from "zod";
|
|
2
2
|
import { getRequestHeader } from "../common/request-context.js";
|
|
3
|
-
import { findAutoResolveConfig, autoResolveViewIdAndFolderPath } from "./client/auto-resolve.js";
|
|
3
|
+
import { extractProjectContext, findAutoResolveConfig, autoResolveViewIdAndFolderPath } from "./client/auto-resolve.js";
|
|
4
4
|
import { QMETRY_HANDLER_MAP } from "./client/handlers.js";
|
|
5
5
|
import { getProjectInfo } from "./client/project.js";
|
|
6
6
|
import { TOOLS } from "./client/tools/index.js";
|
|
7
|
-
import { QMETRY_DEFAULTS } from "./config/constants.js";
|
|
7
|
+
import { QMETRY_DEFAULTS, QMetryToolsHandlers } from "./config/constants.js";
|
|
8
8
|
const ConfigurationSchema = zod__default.object({
|
|
9
9
|
api_key: zod__default.string().describe("QMetry API key for authentication"),
|
|
10
10
|
base_url: zod__default.string().url().optional().describe(
|
|
@@ -19,6 +19,8 @@ class QmetryClient {
|
|
|
19
19
|
token;
|
|
20
20
|
projectApiKey = QMETRY_DEFAULTS.PROJECT_KEY;
|
|
21
21
|
endpoint = QMETRY_DEFAULTS.BASE_URL;
|
|
22
|
+
projectNumericId;
|
|
23
|
+
orgCode;
|
|
22
24
|
async configure(_server, config, _cache) {
|
|
23
25
|
this.token = config.api_key;
|
|
24
26
|
if (config.base_url) {
|
|
@@ -42,6 +44,11 @@ class QmetryClient {
|
|
|
42
44
|
getBaseUrl() {
|
|
43
45
|
return this.endpoint;
|
|
44
46
|
}
|
|
47
|
+
persistProjectContext(projectInfo) {
|
|
48
|
+
const { scopeId, orgCode } = extractProjectContext(projectInfo);
|
|
49
|
+
if (scopeId !== void 0) this.projectNumericId = scopeId;
|
|
50
|
+
if (orgCode !== void 0) this.orgCode = orgCode;
|
|
51
|
+
}
|
|
45
52
|
async registerTools(register, _getInput) {
|
|
46
53
|
const resolveContext = (args) => ({
|
|
47
54
|
baseUrl: args.baseUrl ?? this.endpoint,
|
|
@@ -101,15 +108,35 @@ class QmetryClient {
|
|
|
101
108
|
autoResolveConfig
|
|
102
109
|
)
|
|
103
110
|
);
|
|
111
|
+
this.persistProjectContext(projectInfo);
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
const { projectKey: _, baseUrl: __, ...cleanArgs } = a;
|
|
115
|
+
const SCOPE_AWARE_HANDLERS = /* @__PURE__ */ new Set([
|
|
116
|
+
QMetryToolsHandlers.FETCH_TESTCASE_RUNS_BY_TESTSUITE_RUN,
|
|
117
|
+
QMetryToolsHandlers.BULK_UPDATE_TEST_RUN_UDFS,
|
|
118
|
+
QMetryToolsHandlers.FETCH_TEST_RUN_UDF_METADATA,
|
|
119
|
+
QMetryToolsHandlers.FETCH_TEST_RUN_UDF_VALUES,
|
|
120
|
+
QMetryToolsHandlers.FETCH_CASCADE_CHILD_VALUES
|
|
121
|
+
]);
|
|
122
|
+
const isScopeAware = SCOPE_AWARE_HANDLERS.has(tool.handler);
|
|
123
|
+
const enrichedArgs = {
|
|
124
|
+
...cleanArgs,
|
|
125
|
+
...isScopeAware && this.projectNumericId !== void 0 && {
|
|
126
|
+
scopeId: this.projectNumericId
|
|
127
|
+
},
|
|
128
|
+
...isScopeAware && this.orgCode !== void 0 && { orgCode: this.orgCode }
|
|
129
|
+
};
|
|
107
130
|
const result = await handlerFn(
|
|
108
131
|
this.getToken(),
|
|
109
132
|
baseUrl,
|
|
110
133
|
projectKey,
|
|
111
|
-
|
|
134
|
+
enrichedArgs
|
|
112
135
|
);
|
|
136
|
+
if (tool.handler === QMetryToolsHandlers.SET_PROJECT_INFO) {
|
|
137
|
+
this.projectApiKey = projectKey;
|
|
138
|
+
this.persistProjectContext(result);
|
|
139
|
+
}
|
|
113
140
|
const formatted = tool.formatResponse ? tool.formatResponse(result) : result ?? {};
|
|
114
141
|
return {
|
|
115
142
|
content: [
|
|
@@ -2,6 +2,58 @@ const QMETRY_DEFAULTS = {
|
|
|
2
2
|
BASE_URL: "https://testmanagement.qmetry.com",
|
|
3
3
|
PROJECT_KEY: "default"
|
|
4
4
|
};
|
|
5
|
+
const UDF_MODULES = [
|
|
6
|
+
{ id: 1, name: "Requirement" },
|
|
7
|
+
{ id: 3, name: "Test Case" },
|
|
8
|
+
{ id: 5, name: "Test Step" },
|
|
9
|
+
{ id: 6, name: "Test Suite" },
|
|
10
|
+
{ id: 11, name: "Issue" },
|
|
11
|
+
{ id: 32, name: "Test Run" }
|
|
12
|
+
];
|
|
13
|
+
const UDF_FIELD_TYPES = [
|
|
14
|
+
{
|
|
15
|
+
Id: 6,
|
|
16
|
+
Fieldtype: "STRING",
|
|
17
|
+
Description: "Any text string can be entered in this field in plain text.",
|
|
18
|
+
Preview: "ad-string-ico"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
Id: 2,
|
|
22
|
+
Fieldtype: "LARGETEXT",
|
|
23
|
+
Description: "A large plain text field.",
|
|
24
|
+
Preview: "ad-large-text-ico"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
Id: 3,
|
|
28
|
+
Fieldtype: "LOOKUPLIST",
|
|
29
|
+
Description: "An input which can be associated to any custom list define within the current project. Only one item can be selected at a time from this list.",
|
|
30
|
+
Preview: "ad-lookup-list-ico"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
Id: 4,
|
|
34
|
+
Fieldtype: "MULTILOOKUPLIST",
|
|
35
|
+
Description: "An input which can be associated to any custom list define within the current project. Multiple is can be selected at a time.",
|
|
36
|
+
Preview: "ad-multi-select-lookup-list-ico"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
Id: 5,
|
|
40
|
+
Fieldtype: "NUMBER",
|
|
41
|
+
Description: "Any number can be entered into this field.",
|
|
42
|
+
Preview: "ad-number-ico"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
Id: 1,
|
|
46
|
+
Fieldtype: "DATETIMEPICKER",
|
|
47
|
+
Description: "This will open a calendar control which will allow the user to select a date.",
|
|
48
|
+
Preview: "ad-date-picker-ico"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
Id: 7,
|
|
52
|
+
Fieldtype: "CASCADINGLIST",
|
|
53
|
+
Description: "A single-level cascading select list where child values depend on the parent selection.",
|
|
54
|
+
Preview: "ad-cascading-list-ico"
|
|
55
|
+
}
|
|
56
|
+
];
|
|
5
57
|
const QMetryToolsHandlers = {
|
|
6
58
|
FETCH_PROJECTS: "getProjects",
|
|
7
59
|
SET_PROJECT_INFO: "setProjectInfo",
|
|
@@ -42,9 +94,18 @@ const QMetryToolsHandlers = {
|
|
|
42
94
|
FETCH_AUTOMATION_STATUS: "fetchAutomationStatus",
|
|
43
95
|
CREATE_RELEASE: "createRelease",
|
|
44
96
|
CREATE_CYCLE: "createCycle",
|
|
45
|
-
UPDATE_CYCLE: "updateCycle"
|
|
97
|
+
UPDATE_CYCLE: "updateCycle",
|
|
98
|
+
FETCH_UDF_FIELD_TYPES: "fetchUdfFieldTypes",
|
|
99
|
+
FETCH_UDF_MODULES: "fetchUdfModules",
|
|
100
|
+
BULK_UPDATE_TEST_RUN_UDFS: "bulkUpdateTestRunUdfs",
|
|
101
|
+
FETCH_TEST_RUN_UDF_METADATA: "fetchTestRunUdfMetadata",
|
|
102
|
+
FETCH_TEST_RUN_UDF_VALUES: "fetchTestRunUdfValues",
|
|
103
|
+
FETCH_ISSUE_EXECUTIONS: "getIssueExecutions",
|
|
104
|
+
FETCH_CASCADE_CHILD_VALUES: "fetchCascadeChildValues"
|
|
46
105
|
};
|
|
47
106
|
export {
|
|
48
107
|
QMETRY_DEFAULTS,
|
|
49
|
-
QMetryToolsHandlers
|
|
108
|
+
QMetryToolsHandlers,
|
|
109
|
+
UDF_FIELD_TYPES,
|
|
110
|
+
UDF_MODULES
|
|
50
111
|
};
|
|
@@ -40,11 +40,17 @@ const QMETRY_PATHS = {
|
|
|
40
40
|
GET_ISSUES_LIST: "/rest/issues/list/viewColumns",
|
|
41
41
|
CREATE_UPDATE_ISSUE: "/rest/issues",
|
|
42
42
|
GET_ISSUES_LINKED_TO_TC: "/rest/issues/list/ForTC",
|
|
43
|
-
LINK_ISSUES_TO_TESTCASE_RUN: "/rest/execution/link/issue"
|
|
43
|
+
LINK_ISSUES_TO_TESTCASE_RUN: "/rest/execution/link/issue",
|
|
44
|
+
GET_ISSUE_EXECUTIONS: "/rest/execution/getExecutionsForIssue"
|
|
44
45
|
},
|
|
45
46
|
AUTOMATION: {
|
|
46
47
|
IMPORT_RESULTS: "/rest/import/createandscheduletestresults/1",
|
|
47
48
|
GET_STATUS: "/rest/admin/status/automation/:requestID"
|
|
49
|
+
},
|
|
50
|
+
UDF: {
|
|
51
|
+
BULK_UPDATE_TEST_RUN_UDFS: "/rest/execution/udf/bulkupdate",
|
|
52
|
+
TEST_RUN_UDF_METADATA: "/rest/admin/udf/metadata",
|
|
53
|
+
FETCH_CASCADE_CHILD_VALUES: "/rest/admin/udf/cascade/childValue"
|
|
48
54
|
}
|
|
49
55
|
};
|
|
50
56
|
export {
|
|
@@ -34,15 +34,15 @@ const SkipWarningEnum = z.enum(["0", "1"]);
|
|
|
34
34
|
const CommonFields = {
|
|
35
35
|
projectKey: z.string().describe("Project key - unique identifier for the project").default(QMETRY_DEFAULTS.PROJECT_KEY),
|
|
36
36
|
projectKeyOptional: z.string().optional().describe("Project key - unique identifier for the project").default(QMETRY_DEFAULTS.PROJECT_KEY),
|
|
37
|
-
baseUrl: z.string().url().optional().describe("The base URL for the QMetry instance (must be a valid URL)")
|
|
37
|
+
baseUrl: z.string().url().optional().describe("The base URL for the QMetry instance (must be a valid URL)"),
|
|
38
38
|
start: z.number().optional().describe("Start index for pagination - defaults to 0").default(0),
|
|
39
39
|
page: z.number().optional().describe("Page number to return (starts from 1)").default(1),
|
|
40
40
|
limit: z.number().optional().describe("Number of records (default 10).").default(10),
|
|
41
|
-
tcID: z.number().describe(
|
|
42
|
-
"Test Case numeric ID. This is the internal numeric identifier, not the entity key like 'MAC-TC-1684'. You can get this ID from test case search results or by using filters."
|
|
41
|
+
tcID: z.coerce.number().describe(
|
|
42
|
+
"Test Case numeric ID. CRITICAL: the parameter name is 'tcID' — do NOT use 'testCaseId', 'testCaseID', 'tcId', or other variants. Accepts a string or number. This is the internal numeric identifier, not the entity key like 'MAC-TC-1684'. You can get this ID from test case search results or by using filters."
|
|
43
43
|
),
|
|
44
|
-
id: z.number().describe(
|
|
45
|
-
"Test Case numeric ID (required for fetching steps or version details). This is the internal numeric identifier, not the entity key like 'MAC-TC-1684'. You can get this ID from test case search results."
|
|
44
|
+
id: z.coerce.number().describe(
|
|
45
|
+
"Test Case numeric ID (required for fetching steps or version details). Accepts a string or number. This is the internal numeric identifier, not the entity key like 'MAC-TC-1684'. You can get this ID from test case search results."
|
|
46
46
|
),
|
|
47
47
|
version: z.number().describe(
|
|
48
48
|
"Test Case version number. This is the internal numeric identifier for the version."
|
|
@@ -59,10 +59,10 @@ const CommonFields = {
|
|
|
59
59
|
rqVersion: z.number().describe(
|
|
60
60
|
"Requirement version number (required for fetching specific requirement version details). This is the internal numeric identifier for the version."
|
|
61
61
|
),
|
|
62
|
-
tcViewId: z.number().describe(
|
|
62
|
+
tcViewId: z.number().optional().describe(
|
|
63
63
|
"ViewId for test cases - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.TC.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
64
64
|
),
|
|
65
|
-
rqViewId: z.number().describe(
|
|
65
|
+
rqViewId: z.number().optional().describe(
|
|
66
66
|
"ViewId for requirements - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.RQ.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
67
67
|
),
|
|
68
68
|
rqFolderPath: z.string().optional().describe(
|
|
@@ -77,28 +77,28 @@ const CommonFields = {
|
|
|
77
77
|
folderID: z.number().optional().describe(
|
|
78
78
|
"Folder ID - unique numeric identifier for the specific folder. Use this to target a specific folder within the project hierarchy. Applies to any entity type (test cases, requirements, test suites, etc.)."
|
|
79
79
|
),
|
|
80
|
-
tsFolderID: z.number().describe(
|
|
81
|
-
"Test Suite folder ID
|
|
80
|
+
tsFolderID: z.coerce.number().describe(
|
|
81
|
+
"Test Suite folder ID. CRITICAL: the parameter name is 'tsFolderID' — do NOT use 'testSuiteFolderId', 'folderId', 'folderID', or other variants. Accepts a string or number. Get from project info response → rootFolders.TS.id. Use FETCH_PROJECT_INFO tool first if not provided by user."
|
|
82
82
|
),
|
|
83
|
-
tsID: z.number().describe(
|
|
84
|
-
"Test Suite numeric ID
|
|
83
|
+
tsID: z.coerce.number().describe(
|
|
84
|
+
"Test Suite numeric ID. CRITICAL: the parameter name is 'tsID' — do NOT use 'testSuiteId', 'testSuiteID', 'suiteId', or other variants. Accepts a string or number. NOTE: To get the tsID - Call API 'Testsuite/Fetch Testsuite' From the response, get value of following attribute -> data[<index>].id"
|
|
85
85
|
),
|
|
86
86
|
gridName: z.string().optional().describe("Grid Name to be displayed (default 'TESTEXECUTIONLIST')"),
|
|
87
87
|
teViewId: z.number().optional().describe(
|
|
88
88
|
"ViewId for test execution - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.TE.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
89
89
|
),
|
|
90
|
-
tsfeViewId: z.number().describe(
|
|
90
|
+
tsfeViewId: z.number().optional().describe(
|
|
91
91
|
"ViewId for test suite folders - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.TSFS.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
92
92
|
),
|
|
93
|
-
tsViewId: z.number().describe(
|
|
93
|
+
tsViewId: z.number().optional().describe(
|
|
94
94
|
"ViewId for test suites - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.TS.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
95
95
|
),
|
|
96
|
-
tsrunID: z.string().describe(
|
|
97
|
-
"Test Suite Run ID
|
|
96
|
+
tsrunID: z.coerce.string().describe(
|
|
97
|
+
"Test Suite Run ID. CRITICAL: the parameter name is 'tsrunID' — do NOT use 'testSuiteRunId', 'tsRunID', 'testSuiteRunID', or any other variant. Accepts a string or number (e.g. 731600 or '731600' — both are valid). To get this value: Call 'Fetch Executions by Test Suite' → use data[<index>].tsRunID from the response."
|
|
98
98
|
),
|
|
99
99
|
showTcWithDefects: z.boolean().optional().describe("Show test case runs with linked defects").default(false),
|
|
100
|
-
entityId: z.number().describe(
|
|
101
|
-
"Id of Test case run (required for fetching linked issues).
|
|
100
|
+
entityId: z.coerce.number().describe(
|
|
101
|
+
"Id of Test case run (required for fetching linked issues). CRITICAL: the parameter name is 'entityId' — do NOT use 'tcRunId', 'testCaseRunId', 'runId', or other variants. Accepts a string or number. NOTE: To get the entityId - Call API 'Execution/Fetch Testcase Run ID' From the response, get value of following attribute -> data[<index>].tcRunID"
|
|
102
102
|
),
|
|
103
103
|
getLinked: z.boolean().optional().describe(
|
|
104
104
|
"True to get only those issues that are linked with this Test case Run, False to get those issues which are not linked with this Test case Run. Default value true (get linked issues)."
|
|
@@ -109,6 +109,9 @@ const CommonFields = {
|
|
|
109
109
|
).default("project"),
|
|
110
110
|
filter: z.string().optional().describe("Filter criteria as JSON string (default '[]')").default("[]"),
|
|
111
111
|
udfFilter: z.string().optional().describe("User-defined field filter as JSON string (default '[]')").default("[]"),
|
|
112
|
+
tcrUdfFilter: z.string().optional().describe(
|
|
113
|
+
`Test Case Run (TCR) UDF filter as JSON string (default '[]'). Used to filter test case runs by Test Run UDF field values. Format: '[{"type":"list","value":[<listItemId1>,<listItemId2>],"field":"<udfFieldKey>"}]'. Example: '[{"type":"list","value":[5108701,5108697],"field":"8260LUP"}]' filters runs where the UDF field '8260LUP' has those list item IDs.`
|
|
114
|
+
).default("[]"),
|
|
112
115
|
showRootOnly: z.boolean().optional().describe("Whether to show only root folders."),
|
|
113
116
|
getSubEntities: z.boolean().optional().describe("Whether to include sub-entities."),
|
|
114
117
|
getColumns: z.boolean().optional().describe("Whether to get column information in response.").default(true),
|
|
@@ -242,7 +245,9 @@ const UpdateTestCaseRemoveStepSchema = z.object({
|
|
|
242
245
|
tcsIsParameterized: z.boolean()
|
|
243
246
|
});
|
|
244
247
|
const CreateTestCaseArgsSchema = z.object({
|
|
245
|
-
tcFolderID: z.string()
|
|
248
|
+
tcFolderID: z.string().optional().describe(
|
|
249
|
+
"Test Case folder ID - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific folder ID. System will fetch project info using the projectKey and extract rootFolders.TC.id automatically. Manual folder ID only needed if you want to target a specific sub-folder."
|
|
250
|
+
),
|
|
246
251
|
steps: z.array(CreateTestCaseStepSchema).optional(),
|
|
247
252
|
name: z.string(),
|
|
248
253
|
priority: z.number().optional(),
|
|
@@ -420,18 +425,20 @@ const TestCasesLinkedToRequirementArgsSchema = z.object({
|
|
|
420
425
|
tcFolderPath: z.string().optional().describe(
|
|
421
426
|
'Folder path to get test cases under specific folder. Use empty string "" for root folder or specify path like "/Sample Template".'
|
|
422
427
|
).default(""),
|
|
423
|
-
releaseID: z.string().optional().describe(
|
|
424
|
-
"Filter test cases by release ID.
|
|
428
|
+
releaseID: z.coerce.string().optional().describe(
|
|
429
|
+
"Filter test cases by release ID. Accepts a string or number. Get release IDs from FETCH_RELEASES_AND_CYCLES tool."
|
|
425
430
|
),
|
|
426
|
-
cycleID: z.string().optional().describe(
|
|
427
|
-
"Filter test cases by cycle ID.
|
|
431
|
+
cycleID: z.coerce.string().optional().describe(
|
|
432
|
+
"Filter test cases by cycle ID. Accepts a string or number. Get cycle IDs from FETCH_RELEASES_AND_CYCLES tool."
|
|
428
433
|
),
|
|
429
434
|
filter: CommonFields.filter,
|
|
430
435
|
getSubEntities: z.boolean().optional().describe("Allow filter of sub-entities for requirement.").default(true),
|
|
431
436
|
getColumns: z.boolean().optional().describe("True to get column information in response.").default(true)
|
|
432
437
|
});
|
|
433
438
|
const CreateTestSuiteArgsSchema = z.object({
|
|
434
|
-
parentFolderId: z.string()
|
|
439
|
+
parentFolderId: z.string().optional().describe(
|
|
440
|
+
"Test Suite parent folder ID - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific folder ID. System will fetch project info using the projectKey and extract rootFolders.TS.id automatically. Manual folder ID only needed if you want to target a specific sub-folder."
|
|
441
|
+
),
|
|
435
442
|
name: z.string(),
|
|
436
443
|
isAutomatedFlag: z.boolean().optional(),
|
|
437
444
|
description: z.string().optional(),
|
|
@@ -447,7 +454,9 @@ const CreateTestSuiteArgsSchema = z.object({
|
|
|
447
454
|
});
|
|
448
455
|
const UpdateTestSuiteArgsSchema = z.object({
|
|
449
456
|
id: z.number().describe("Id of Test Suite to be updated (required)"),
|
|
450
|
-
TsFolderID: z.number().describe(
|
|
457
|
+
TsFolderID: z.number().optional().describe(
|
|
458
|
+
"Folder ID where Test Suite resides - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific folder ID. System will fetch project info using the projectKey and extract rootFolders.TS.id automatically. Manual folder ID only needed if you want to override the automatic resolution."
|
|
459
|
+
),
|
|
451
460
|
entityKey: z.string().describe("Entity Key of Test Suite to be updated (required)"),
|
|
452
461
|
name: z.string().optional().describe("Name of the Test Suite"),
|
|
453
462
|
description: z.string().optional().describe("Description of the Test Suite"),
|
|
@@ -473,8 +482,8 @@ const TestSuiteListArgsSchema = z.object({
|
|
|
473
482
|
const TestSuitesForTestCaseArgsSchema = z.object({
|
|
474
483
|
projectKey: CommonFields.projectKeyOptional,
|
|
475
484
|
baseUrl: CommonFields.baseUrl,
|
|
476
|
-
tsFolderID: CommonFields.tsFolderID,
|
|
477
|
-
viewId: CommonFields.tsfeViewId
|
|
485
|
+
tsFolderID: CommonFields.tsFolderID.optional(),
|
|
486
|
+
viewId: CommonFields.tsfeViewId,
|
|
478
487
|
start: CommonFields.start,
|
|
479
488
|
page: CommonFields.page,
|
|
480
489
|
limit: CommonFields.limit,
|
|
@@ -482,16 +491,20 @@ const TestSuitesForTestCaseArgsSchema = z.object({
|
|
|
482
491
|
filter: CommonFields.filter
|
|
483
492
|
});
|
|
484
493
|
const LinkTestCasesToTestSuiteArgsSchema = z.object({
|
|
485
|
-
tsID: z.number().describe(
|
|
486
|
-
|
|
487
|
-
|
|
494
|
+
tsID: z.coerce.number().describe(
|
|
495
|
+
"Id of Test Suite (required). CRITICAL: parameter name is 'tsID' — do NOT use 'testSuiteId', 'testSuiteID', or other variants."
|
|
496
|
+
),
|
|
497
|
+
tcvdIDs: z.array(z.coerce.number()).describe(
|
|
498
|
+
"Array of Test Case Version IDs (required if fromReqs is false). CRITICAL: parameter name is 'tcvdIDs' — do NOT use 'tcVersionIds', 'testCaseVersionIds', or other variants."
|
|
488
499
|
),
|
|
489
500
|
fromReqs: z.boolean().optional().describe("Link TestCases from Requirements (optional, default false)")
|
|
490
501
|
}).strip();
|
|
491
502
|
const RequirementsLinkedTestCasesToTestSuiteArgsSchema = z.object({
|
|
492
|
-
tsID: z.number().describe(
|
|
493
|
-
|
|
494
|
-
|
|
503
|
+
tsID: z.coerce.number().describe(
|
|
504
|
+
"Id of Test Suite (required). CRITICAL: parameter name is 'tsID' — do NOT use 'testSuiteId', 'testSuiteID', or other variants."
|
|
505
|
+
),
|
|
506
|
+
tcvdIDs: z.array(z.coerce.number()).describe(
|
|
507
|
+
"Array of Test Case Version IDs (required if fromReqs is true). CRITICAL: parameter name is 'tcvdIDs' — do NOT use 'tcVersionIds', 'testCaseVersionIds', or other variants."
|
|
495
508
|
),
|
|
496
509
|
fromReqs: z.boolean().optional().describe("Link TestCases from Requirements (optional, default true)")
|
|
497
510
|
}).strip();
|
|
@@ -533,11 +546,15 @@ const TestCaseRunsByTestSuiteRunArgsSchema = z.object({
|
|
|
533
546
|
baseUrl: CommonFields.baseUrl,
|
|
534
547
|
tsrunID: CommonFields.tsrunID,
|
|
535
548
|
// API payload param - sent in request body (REQUIRED)
|
|
536
|
-
viewId: CommonFields.teViewId
|
|
537
|
-
//
|
|
549
|
+
viewId: CommonFields.teViewId,
|
|
550
|
+
// auto-resolved via SYSTEM if not provided
|
|
538
551
|
start: CommonFields.start,
|
|
539
552
|
page: CommonFields.page,
|
|
540
|
-
limit: CommonFields.limit
|
|
553
|
+
limit: CommonFields.limit,
|
|
554
|
+
filter: CommonFields.filter,
|
|
555
|
+
udfFilter: CommonFields.udfFilter,
|
|
556
|
+
tcrUdfFilter: CommonFields.tcrUdfFilter,
|
|
557
|
+
showTcWithDefects: CommonFields.showTcWithDefects
|
|
541
558
|
});
|
|
542
559
|
const LinkedIssuesByTestCaseRunArgsSchema = z.object({
|
|
543
560
|
projectKey: CommonFields.projectKeyOptional,
|
|
@@ -569,7 +586,9 @@ const CreateIssueArgsSchema = z.object({
|
|
|
569
586
|
)
|
|
570
587
|
});
|
|
571
588
|
const UpdateIssueArgsSchema = z.object({
|
|
572
|
-
DefectId: z.number().describe(
|
|
589
|
+
DefectId: z.coerce.number().describe(
|
|
590
|
+
"ID of the defect/issue to be updated. CRITICAL: the parameter name is 'DefectId' (capital D) — do NOT use 'defectId', 'issueId', 'id', or other variants. Accepts a string or number."
|
|
591
|
+
),
|
|
573
592
|
entityKey: z.string().optional().describe("Entity Key of the defect/issue to be updated"),
|
|
574
593
|
issueType: z.number().optional().describe("Issue type ID (e.g. Bug, Enhancement, etc.)"),
|
|
575
594
|
issuePriority: z.number().optional().describe("Issue priority ID (e.g. High, Medium, Low, etc.)"),
|
|
@@ -582,7 +601,7 @@ const UpdateIssueArgsSchema = z.object({
|
|
|
582
601
|
const IssuesListArgsSchema = z.object({
|
|
583
602
|
projectKey: CommonFields.projectKeyOptional,
|
|
584
603
|
baseUrl: CommonFields.baseUrl,
|
|
585
|
-
viewId: z.number().describe(
|
|
604
|
+
viewId: z.number().optional().describe(
|
|
586
605
|
"ViewId for issues - SYSTEM AUTOMATICALLY RESOLVES THIS. Leave empty unless you have a specific viewId. System will fetch project info using the projectKey and extract latestViews.IS.viewId automatically. Manual viewId only needed if you want to override the automatic resolution."
|
|
587
606
|
),
|
|
588
607
|
start: CommonFields.start,
|
|
@@ -598,29 +617,45 @@ const LinkIssuesToTestcaseRunArgsSchema = z.object({
|
|
|
598
617
|
projectKey: CommonFields.projectKeyOptional,
|
|
599
618
|
baseUrl: CommonFields.baseUrl,
|
|
600
619
|
issueIds: z.array(z.union([z.string(), z.number()])).describe("ID of issues to be linked to Testcase Run"),
|
|
601
|
-
tcrId: z.number().describe(
|
|
620
|
+
tcrId: z.coerce.number().describe(
|
|
621
|
+
"ID of Testcase Run to link issues with. CRITICAL: parameter name is 'tcrId' — do NOT use 'tcRunId', 'testCaseRunId', or other variants. Accepts a string or number."
|
|
622
|
+
)
|
|
623
|
+
});
|
|
624
|
+
const IssueExecutionsArgsSchema = z.object({
|
|
625
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
626
|
+
baseUrl: CommonFields.baseUrl,
|
|
627
|
+
linkedAssetId: z.coerce.number().describe(
|
|
628
|
+
"Numeric defect ID of the QMetry issue. CRITICAL: parameter name is 'linkedAssetId' — do NOT use 'issueId', 'defectId', 'id', or other variants. Accepts a string or number. To get this ID, call the Fetch Defects or Issues tool and use data[<index>].id from the response."
|
|
629
|
+
),
|
|
630
|
+
start: CommonFields.start,
|
|
631
|
+
page: CommonFields.page,
|
|
632
|
+
limit: CommonFields.limit,
|
|
633
|
+
platformID: z.string().optional().describe("Platform ID to filter executions by environment/platform"),
|
|
634
|
+
filter: z.string().optional().describe(
|
|
635
|
+
`JSON filter string. Supported fields: tcName (string), linkageLevel (string), executedVersion (string), runStatusName (list of status names), platformID (list of numeric IDs), executionCreatedByLoginAlias (list of usernames), isTestSuiteArchived (list: [1] active, [0] archived, [1,0] both). Example: '[{"type":"string","value":"login","field":"tcName"}]'`
|
|
636
|
+
).default("[]")
|
|
602
637
|
});
|
|
603
638
|
const LinkPlatformsToTestSuiteArgsSchema = z.object({
|
|
604
639
|
projectKey: CommonFields.projectKeyOptional,
|
|
605
640
|
baseUrl: CommonFields.baseUrl,
|
|
606
|
-
qmTsId: z.number().describe(
|
|
607
|
-
"Id of Test Suite (required). To get the qmTsId - Call API 'Testsuite/Fetch Testsuite' From the response, get value
|
|
641
|
+
qmTsId: z.coerce.number().describe(
|
|
642
|
+
"Id of Test Suite (required). CRITICAL: the parameter name is 'qmTsId' — do NOT use 'tsId', 'testSuiteId', 'tsID', or other variants. Accepts a string or number. To get the qmTsId - Call API 'Testsuite/Fetch Testsuite'. From the response, get value -> data[<index>].id"
|
|
608
643
|
),
|
|
609
|
-
qmPlatformId: z.string().describe(
|
|
610
|
-
"Comma-separated
|
|
644
|
+
qmPlatformId: z.coerce.string().describe(
|
|
645
|
+
"Comma-separated Platform IDs (required). CRITICAL: the parameter name is 'qmPlatformId' — do NOT use 'platformId', 'platformID', 'platformIds', or other variants. Accepts a number or string. To get the qmPlatformId - Call API 'Platform/List'. From the response, get value -> data[<index>].platformID"
|
|
611
646
|
)
|
|
612
647
|
});
|
|
613
648
|
const BulkUpdateExecutionStatusArgsSchema = z.object({
|
|
614
649
|
projectKey: CommonFields.projectKeyOptional,
|
|
615
650
|
baseUrl: CommonFields.baseUrl,
|
|
616
|
-
entityIDs: z.string().describe(
|
|
617
|
-
"Comma-separated IDs of Test Case Runs to update (e.g., '66095087' for single
|
|
651
|
+
entityIDs: z.coerce.string().describe(
|
|
652
|
+
"Comma-separated IDs of Test Case Runs to update. CRITICAL: the parameter name is 'entityIDs' — do NOT use 'tcRunIDs', 'testCaseRunIds', 'runIds', or other variants. Accepts a number or string (e.g., 66095087 or '66095087' for single, '66095069,66095075' for bulk). To get the entityIDs - Call API 'Execution/Fetch Testcase Run ID'. From the response, get value -> data[<index>].tcRunID"
|
|
618
653
|
),
|
|
619
654
|
entityType: z.enum(["TCR", "TCSR"]).describe(
|
|
620
655
|
"Type of Entity to Execute: 'TCR' (Test Case Run) or 'TCSR' (Test Case Step Run)"
|
|
621
656
|
).default("TCR"),
|
|
622
|
-
qmTsRunId: z.string().describe(
|
|
623
|
-
"Id of Test Suite Run to execute (required). To get the qmTsRunId - Call API 'Execution/Fetch Executions' From the response, get value
|
|
657
|
+
qmTsRunId: z.coerce.string().describe(
|
|
658
|
+
"Id of Test Suite Run to execute (required). CRITICAL: the parameter name is 'qmTsRunId' — do NOT use 'tsrunID', 'testSuiteRunId', 'tsRunID', or other variants. Accepts a number or string. To get the qmTsRunId - Call API 'Execution/Fetch Executions'. From the response, get value -> data[<index>].tsRunID"
|
|
624
659
|
),
|
|
625
660
|
runStatusID: z.number().describe(
|
|
626
661
|
"Id of the execution status to set (required). To get the runStatusID - Call API 'Admin/Project GET info Service' From the response, get value of following attribute -> allstatus[<index>].id Common statuses: Pass, Fail, Not Run, Blocked, WIP, etc."
|
|
@@ -718,7 +753,9 @@ const ImportAutomationResultsPayloadSchema = z.object({
|
|
|
718
753
|
const FetchAutomationStatusPayloadSchema = z.object({
|
|
719
754
|
projectKey: CommonFields.projectKeyOptional,
|
|
720
755
|
baseUrl: CommonFields.baseUrl,
|
|
721
|
-
requestID: z.number().describe(
|
|
756
|
+
requestID: z.coerce.number().describe(
|
|
757
|
+
"Numeric request ID from import automation response. CRITICAL: parameter name is 'requestID' — do NOT use 'requestId', 'jobId', or other variants. Accepts a string or number."
|
|
758
|
+
)
|
|
722
759
|
});
|
|
723
760
|
export {
|
|
724
761
|
AutomationHierarchyEnum,
|
|
@@ -739,6 +776,7 @@ export {
|
|
|
739
776
|
ExecutionsByTestSuiteArgsSchema,
|
|
740
777
|
FetchAutomationStatusPayloadSchema,
|
|
741
778
|
ImportAutomationResultsPayloadSchema,
|
|
779
|
+
IssueExecutionsArgsSchema,
|
|
742
780
|
IssuesLinkedToTestCaseArgsSchema,
|
|
743
781
|
IssuesListArgsSchema,
|
|
744
782
|
LinkIssuesToTestcaseRunArgsSchema,
|
|
@@ -7,6 +7,10 @@ const DEFAULT_FETCH_ISSUES_LINKED_TO_TESTCASE_PAYLOAD = {
|
|
|
7
7
|
const DEFAULT_CREATE_ISSUE_PAYLOAD = {};
|
|
8
8
|
const DEFAULT_UPDATE_ISSUE_PAYLOAD = {};
|
|
9
9
|
const DEFAULT_LINK_ISSUES_TO_TESTCASE_RUN_PAYLOAD = {};
|
|
10
|
+
const DEFAULT_FETCH_ISSUE_EXECUTIONS_PAYLOAD = {
|
|
11
|
+
...DEFAULT_PAGINATION,
|
|
12
|
+
filter: "[]"
|
|
13
|
+
};
|
|
10
14
|
const DEFAULT_FETCH_ISSUES_PAYLOAD = {
|
|
11
15
|
...DEFAULT_PAGINATION,
|
|
12
16
|
...DEFAULT_FILTER,
|
|
@@ -23,6 +27,7 @@ export {
|
|
|
23
27
|
DEFAULT_CREATE_ISSUE_PAYLOAD,
|
|
24
28
|
DEFAULT_FETCH_ISSUES_LINKED_TO_TESTCASE_PAYLOAD,
|
|
25
29
|
DEFAULT_FETCH_ISSUES_PAYLOAD,
|
|
30
|
+
DEFAULT_FETCH_ISSUE_EXECUTIONS_PAYLOAD,
|
|
26
31
|
DEFAULT_LINK_ISSUES_TO_TESTCASE_RUN_PAYLOAD,
|
|
27
32
|
DEFAULT_UPDATE_ISSUE_PAYLOAD
|
|
28
33
|
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CommonFields } from "./common.js";
|
|
3
|
+
z.object({
|
|
4
|
+
projectKey: CommonFields.projectKey,
|
|
5
|
+
baseUrl: CommonFields.baseUrl
|
|
6
|
+
});
|
|
7
|
+
z.object({
|
|
8
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
9
|
+
baseUrl: CommonFields.baseUrl
|
|
10
|
+
});
|
|
11
|
+
const UdfFieldValueSchema = z.object({
|
|
12
|
+
fieldID: z.number().int().positive().describe(
|
|
13
|
+
"Numeric ID of the UDF field to update. Get this from the UDF field definition in QMetry admin or from the field's metadata."
|
|
14
|
+
),
|
|
15
|
+
value: z.union([
|
|
16
|
+
z.string(),
|
|
17
|
+
z.number(),
|
|
18
|
+
z.array(z.number().int()),
|
|
19
|
+
z.object({
|
|
20
|
+
parent: z.number().int().describe("Parent item ID for cascading list."),
|
|
21
|
+
child: z.number().int().describe("Child item ID for cascading list.")
|
|
22
|
+
})
|
|
23
|
+
]).describe(
|
|
24
|
+
"Value to set for this UDF field. Type depends on field type:\nSTRING: plain string, e.g. 'test value'\nNUMBER: number, e.g. 3\nDATETIMEPICKER: date string in MM-DD-YYYY format, e.g. '06-20-2026'\nLOOKUPLIST (single): numeric item ID, e.g. 5108697\nMULTILOOKUPLIST (multi-select): array of item IDs, e.g. [5158524, 5158525]\nCASCADINGLIST: object with parent and child IDs, e.g. {parent: 5126498, child: 5126499}"
|
|
25
|
+
),
|
|
26
|
+
multiSelectAction: z.enum(["append", "replace"]).optional().default("append").describe(
|
|
27
|
+
"Action for MULTILOOKUPLIST fields only. 'append' adds the new values to existing selections (default). 'replace' clears existing selections and sets only the new values. Omit or use 'append' if user does not specify — never assume 'replace'."
|
|
28
|
+
)
|
|
29
|
+
});
|
|
30
|
+
const BulkUpdateTestRunUdfsArgsSchema = z.object({
|
|
31
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
32
|
+
baseUrl: CommonFields.baseUrl,
|
|
33
|
+
tcRunIDs: z.array(z.number().int().positive()).min(1).describe(
|
|
34
|
+
"Array of Test Case Run IDs to update UDF values for. To get tcRunIDs — Call 'Fetch Test Case Runs by Test Suite Run' tool. From the response, get value of data[<index>].tcRunID. Example: [41572006, 41572009, 41572013]"
|
|
35
|
+
),
|
|
36
|
+
UDF: z.record(z.string(), UdfFieldValueSchema).describe(
|
|
37
|
+
"Object mapping UDF field names to their new values. Each key is the UDF field name (e.g. 'test_env', 'priority_field'). Each value is an object with fieldID and value (and optionally multiSelectAction for multi-select fields). All UDF fields are optional — include only the fields you want to update."
|
|
38
|
+
)
|
|
39
|
+
});
|
|
40
|
+
const FetchTestRunUdfMetadataArgsSchema = z.object({
|
|
41
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
42
|
+
baseUrl: CommonFields.baseUrl
|
|
43
|
+
});
|
|
44
|
+
const FetchCascadeChildValuesArgsSchema = z.object({
|
|
45
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
46
|
+
baseUrl: CommonFields.baseUrl,
|
|
47
|
+
id: z.number().int().positive().describe(
|
|
48
|
+
"Numeric ID of the parent cascade list item to fetch child values for. Get this from the 'lookupOptions' returned by 'Fetch Test Run UDF Metadata' for a CASCADINGLIST field — each option has an 'id' field."
|
|
49
|
+
),
|
|
50
|
+
isArchReq: z.boolean().optional().default(false).describe(
|
|
51
|
+
"Whether to include archived child items in the response (default: false)."
|
|
52
|
+
)
|
|
53
|
+
});
|
|
54
|
+
const FetchTestRunUdfValuesArgsSchema = z.object({
|
|
55
|
+
projectKey: CommonFields.projectKeyOptional,
|
|
56
|
+
baseUrl: CommonFields.baseUrl,
|
|
57
|
+
tsrunID: z.coerce.string().optional().describe(
|
|
58
|
+
"Test Suite Run ID. CRITICAL: the parameter name is 'tsrunID' — do NOT use 'testSuiteRunId', 'tsRunID', or any other variant. Accepts a string or number (e.g. 731600 or '731600' — both are valid). Get this from 'Fetch Executions by Test Suite' → use data[<index>].tsRunID from the response. Required when sourceRows is not provided."
|
|
59
|
+
),
|
|
60
|
+
viewId: z.number().int().positive().optional().describe(
|
|
61
|
+
"View ID for the test execution list (latestViews.TE.viewId from project info). Auto-resolved from project info when omitted. Required when sourceRows is not provided."
|
|
62
|
+
),
|
|
63
|
+
sourceContext: z.enum(["testSuiteRun", "testCaseExecutions"]).optional().default("testSuiteRun").describe(
|
|
64
|
+
"Which parent tool produced sourceRows. Use 'testSuiteRun' for Fetch Test Case Runs by Test Suite Run. Do NOT use this tool for Fetch Test Case Executions — that tool calls metadata internally and returns testRunUdfs on every execution row; use that data directly. Do NOT use this tool for Fetch Issue Executions; that tool already reads udfjson and enriches it with metadata."
|
|
65
|
+
),
|
|
66
|
+
sourceRows: z.array(z.record(z.string(), z.unknown())).optional().describe(
|
|
67
|
+
"Optional rows already returned by Fetch Test Case Runs by Test Suite Run. The UDF tool will reuse these rows, enrich/pivot UDF values, and preserve identification fields instead of making the same execution-list API call again. Do NOT pass Fetch Test Case Executions rows here — those rows already have testRunUdfs enriched. Do not pass issue execution rows here; use Fetch Issue Executions output directly for issue UDFs."
|
|
68
|
+
),
|
|
69
|
+
startIndex: z.number().int().min(0).optional().default(0).describe("Zero-based start index for pagination (default: 0)."),
|
|
70
|
+
size: z.number().int().min(1).optional().default(50).describe("Number of test case runs to return per page (default: 50).")
|
|
71
|
+
});
|
|
72
|
+
export {
|
|
73
|
+
BulkUpdateTestRunUdfsArgsSchema,
|
|
74
|
+
FetchCascadeChildValuesArgsSchema,
|
|
75
|
+
FetchTestRunUdfMetadataArgsSchema,
|
|
76
|
+
FetchTestRunUdfValuesArgsSchema
|
|
77
|
+
};
|