@smartbear/mcp 0.23.0 → 0.25.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.
Files changed (148) hide show
  1. package/README.md +10 -2
  2. package/dist/bearq/client.js +12 -13
  3. package/dist/bearq/tool/tasks/chat-with-qa-lead.js +1 -0
  4. package/dist/bearq/tool/tasks/expand-application-model.js +1 -0
  5. package/dist/bearq/tool/tasks/get-task-status.js +1 -0
  6. package/dist/bearq/tool/tasks/get-task.js +1 -0
  7. package/dist/bearq/tool/tasks/refine-all-draft-tests.js +1 -0
  8. package/dist/bearq/tool/tasks/refine-test-cases.js +1 -0
  9. package/dist/bearq/tool/tasks/refine-tests-in-functional-areas.js +1 -0
  10. package/dist/bearq/tool/tasks/run-regression-tests.js +1 -0
  11. package/dist/bearq/tool/tasks/run-test-cases.js +1 -0
  12. package/dist/bearq/tool/tasks/run-tests-in-functional-areas.js +1 -0
  13. package/dist/bearq/tool/tasks/stop-task.js +1 -0
  14. package/dist/bearq/tool/tasks/wait-for-task.js +1 -0
  15. package/dist/bugsnag/client.js +24 -44
  16. package/dist/bugsnag/tool/error/get-error.js +1 -0
  17. package/dist/bugsnag/tool/error/list-project-errors.js +1 -0
  18. package/dist/bugsnag/tool/error/update-error.js +1 -0
  19. package/dist/bugsnag/tool/event/get-event-details-from-dashboard-url.js +1 -0
  20. package/dist/bugsnag/tool/event/get-event.js +1 -0
  21. package/dist/bugsnag/tool/event/list-error-events.js +1 -0
  22. package/dist/bugsnag/tool/performance/get-network-endpoint-groupings.js +1 -0
  23. package/dist/bugsnag/tool/performance/get-span-group.js +1 -0
  24. package/dist/bugsnag/tool/performance/get-trace.js +1 -0
  25. package/dist/bugsnag/tool/performance/list-span-groups.js +1 -0
  26. package/dist/bugsnag/tool/performance/list-spans.js +1 -0
  27. package/dist/bugsnag/tool/performance/list-trace-fields.js +1 -0
  28. package/dist/bugsnag/tool/performance/set-network-endpoint-groupings.js +1 -0
  29. package/dist/bugsnag/tool/project/get-current-project.js +1 -0
  30. package/dist/bugsnag/tool/project/list-project-event-filters.js +1 -0
  31. package/dist/bugsnag/tool/project/list-projects.js +1 -0
  32. package/dist/bugsnag/tool/release/get-build.js +1 -0
  33. package/dist/bugsnag/tool/release/get-release.js +1 -0
  34. package/dist/bugsnag/tool/release/list-releases.js +1 -0
  35. package/dist/collaborator/client.js +24 -19
  36. package/dist/common/client-registry.js +63 -29
  37. package/dist/common/server.js +57 -1
  38. package/dist/common/transport-http.js +90 -69
  39. package/dist/common/transport-stdio.js +29 -24
  40. package/dist/package.json.js +1 -1
  41. package/dist/pactflow/client/base.js +3 -3
  42. package/dist/pactflow/client/tools.js +102 -0
  43. package/dist/pactflow/client.js +30 -43
  44. package/dist/qmetry/client/tools/automation-tools.js +2 -0
  45. package/dist/qmetry/client/tools/issue-tools.js +6 -0
  46. package/dist/qmetry/client/tools/project-tools.js +9 -0
  47. package/dist/qmetry/client/tools/requirement-tools.js +5 -0
  48. package/dist/qmetry/client/tools/testcase-tools.js +7 -0
  49. package/dist/qmetry/client/tools/testsuite-tools.js +11 -0
  50. package/dist/qmetry/client.js +20 -18
  51. package/dist/qtm4j/client.js +57 -23
  52. package/dist/qtm4j/config/constants.js +197 -5
  53. package/dist/qtm4j/config/field-resolution.types.js +5 -2
  54. package/dist/qtm4j/http/api-client.js +90 -3
  55. package/dist/qtm4j/resolver/cache/cache.js +1 -1
  56. package/dist/qtm4j/resolver/resolver-registry.js +7 -1
  57. package/dist/qtm4j/resolver/resolvers/common-attribute-resolver.js +1 -0
  58. package/dist/qtm4j/resolver/resolvers/component-resolver.js +2 -0
  59. package/dist/qtm4j/resolver/resolvers/label-resolver.js +2 -0
  60. package/dist/qtm4j/resolver/resolvers/requirement-id-resolver.js +28 -0
  61. package/dist/qtm4j/resolver/resolvers/test-cycle-uid-resolver.js +28 -0
  62. package/dist/qtm4j/schema/automation.schema.js +107 -0
  63. package/dist/qtm4j/schema/linked-items.schema.js +95 -0
  64. package/dist/qtm4j/schema/requirements.schema.js +109 -0
  65. package/dist/qtm4j/schema/search-test-cycle.schema.js +133 -0
  66. package/dist/qtm4j/schema/test-cycle.link.schema.js +260 -0
  67. package/dist/qtm4j/schema/test-cycle.schema.js +39 -0
  68. package/dist/qtm4j/schema/update-test-cycle.schema.js +54 -0
  69. package/dist/qtm4j/tool/project/get-projects.js +2 -1
  70. package/dist/qtm4j/tool/project/set-project-context.js +2 -1
  71. package/dist/qtm4j/tool/requirement/get-linked-testcases.js +93 -0
  72. package/dist/qtm4j/tool/requirement/link-testcases.js +107 -0
  73. package/dist/qtm4j/tool/requirement/unlink-testcases.js +97 -0
  74. package/dist/qtm4j/tool/test-automation/get-automation-history.js +70 -0
  75. package/dist/qtm4j/tool/test-automation/upload-automation-result.js +144 -0
  76. package/dist/qtm4j/tool/test-case/create-test-case.js +2 -1
  77. package/dist/qtm4j/tool/test-case/get-linked-requirements.js +67 -0
  78. package/dist/qtm4j/tool/test-case/get-test-cases.js +2 -1
  79. package/dist/qtm4j/tool/test-case/get-test-steps.js +2 -1
  80. package/dist/qtm4j/tool/test-case/link-requirements.js +124 -0
  81. package/dist/qtm4j/tool/test-case/unlink-requirements.js +116 -0
  82. package/dist/qtm4j/tool/test-case/update-test-case.js +2 -1
  83. package/dist/qtm4j/tool/test-cycle/create-test-cycle.js +81 -0
  84. package/dist/qtm4j/tool/test-cycle/get-linked-requirements.js +71 -0
  85. package/dist/qtm4j/tool/test-cycle/link-requirements.js +91 -0
  86. package/dist/qtm4j/tool/test-cycle/link-testcases.js +118 -0
  87. package/dist/qtm4j/tool/test-cycle/search-linked-testcases.js +114 -0
  88. package/dist/qtm4j/tool/test-cycle/search-test-cycle.js +137 -0
  89. package/dist/qtm4j/tool/test-cycle/unlink-requirements.js +87 -0
  90. package/dist/qtm4j/tool/test-cycle/unlink-testcases.js +103 -0
  91. package/dist/qtm4j/tool/test-cycle/update-test-cycle.js +162 -0
  92. package/dist/reflect/client.js +15 -24
  93. package/dist/reflect/config/constants.js +0 -2
  94. package/dist/reflect/tool/recording/add-prompt-step.js +1 -0
  95. package/dist/reflect/tool/recording/add-segment.js +1 -0
  96. package/dist/reflect/tool/recording/connect-to-session.js +1 -0
  97. package/dist/reflect/tool/recording/delete-previous-step.js +1 -0
  98. package/dist/reflect/tool/recording/get-screenshot.js +1 -0
  99. package/dist/reflect/tool/suites/cancel-suite-execution.js +1 -0
  100. package/dist/reflect/tool/suites/execute-suite.js +1 -0
  101. package/dist/reflect/tool/suites/get-suite-execution-status.js +1 -0
  102. package/dist/reflect/tool/suites/list-suite-executions.js +1 -0
  103. package/dist/reflect/tool/suites/list-suites.js +1 -0
  104. package/dist/reflect/tool/tests/get-test-status.js +1 -0
  105. package/dist/reflect/tool/tests/list-segments.js +1 -0
  106. package/dist/reflect/tool/tests/list-tests.js +1 -0
  107. package/dist/reflect/tool/tests/run-test.js +1 -0
  108. package/dist/swagger/client/portal-types.js +1 -1
  109. package/dist/swagger/client/tools.js +23 -0
  110. package/dist/swagger/client.js +25 -28
  111. package/dist/zephyr/client.js +14 -21
  112. package/dist/zephyr/tool/environment/get-environments.js +1 -0
  113. package/dist/zephyr/tool/folder/create-folder.js +1 -0
  114. package/dist/zephyr/tool/issue-link/get-test-cases.js +1 -0
  115. package/dist/zephyr/tool/issue-link/get-test-cycles.js +1 -0
  116. package/dist/zephyr/tool/issue-link/get-test-executions.js +1 -0
  117. package/dist/zephyr/tool/priority/get-priorities.js +1 -0
  118. package/dist/zephyr/tool/project/get-project.js +1 -0
  119. package/dist/zephyr/tool/project/get-projects.js +1 -0
  120. package/dist/zephyr/tool/status/get-statuses.js +1 -0
  121. package/dist/zephyr/tool/test-case/create-issue-link.js +1 -0
  122. package/dist/zephyr/tool/test-case/create-test-case.js +1 -0
  123. package/dist/zephyr/tool/test-case/create-test-script.js +1 -0
  124. package/dist/zephyr/tool/test-case/create-test-steps.js +1 -0
  125. package/dist/zephyr/tool/test-case/create-web-link.js +1 -0
  126. package/dist/zephyr/tool/test-case/get-links.js +1 -0
  127. package/dist/zephyr/tool/test-case/get-test-case.js +1 -0
  128. package/dist/zephyr/tool/test-case/get-test-cases.js +1 -0
  129. package/dist/zephyr/tool/test-case/get-test-script.js +1 -0
  130. package/dist/zephyr/tool/test-case/get-test-steps.js +1 -0
  131. package/dist/zephyr/tool/test-case/update-test-case.js +1 -0
  132. package/dist/zephyr/tool/test-cycle/create-issue-link.js +1 -0
  133. package/dist/zephyr/tool/test-cycle/create-test-cycle.js +1 -0
  134. package/dist/zephyr/tool/test-cycle/create-web-link.js +1 -0
  135. package/dist/zephyr/tool/test-cycle/get-links.js +1 -0
  136. package/dist/zephyr/tool/test-cycle/get-test-cycle.js +1 -0
  137. package/dist/zephyr/tool/test-cycle/get-test-cycles.js +1 -0
  138. package/dist/zephyr/tool/test-cycle/update-test-cycle.js +1 -0
  139. package/dist/zephyr/tool/test-execution/create-issue-link.js +1 -0
  140. package/dist/zephyr/tool/test-execution/create-test-execution.js +1 -0
  141. package/dist/zephyr/tool/test-execution/get-test-execution-links.js +1 -0
  142. package/dist/zephyr/tool/test-execution/get-test-execution.js +1 -0
  143. package/dist/zephyr/tool/test-execution/get-test-executions.js +1 -0
  144. package/dist/zephyr/tool/test-execution/get-test-steps.js +1 -0
  145. package/dist/zephyr/tool/test-execution/update-test-execution.js +1 -0
  146. package/dist/zephyr/tool/test-execution/update-test-steps.js +1 -0
  147. package/package.json +1 -1
  148. package/dist/common/request-context.js +0 -20
@@ -1,27 +1,26 @@
1
1
  import zod__default from "zod";
2
2
  import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
3
3
  import { isSamplingPolyfillResult } from "../common/pollyfills.js";
4
- import { getRequestHeader } from "../common/request-context.js";
5
4
  import { ToolError } from "../common/tools.js";
6
5
  import { getOADMatcherRecommendations, getUserMatcherSelection } from "./client/prompt-utils.js";
7
6
  import { PROMPTS } from "./client/prompts.js";
8
7
  import { TOOLS } from "./client/tools.js";
9
8
  const ConfigurationSchema = zod__default.object({
10
- base_url: zod__default.url().describe("Pact Broker or PactFlow base URL"),
11
- token: zod__default.string().optional().describe(
9
+ base_url: zod__default.url().describe("Pact Broker or PactFlow base URL")
10
+ });
11
+ const AuthenticationSchema = zod__default.object({
12
+ username: zod__default.string().describe("Username for Pact Broker").optional(),
13
+ password: zod__default.string().describe("Password for Pact Broker").optional(),
14
+ token: zod__default.string().describe(
12
15
  "Bearer token for PactFlow authentication (use this OR username/password)"
13
- ),
14
- username: zod__default.string().optional().describe("Username for Pact Broker"),
15
- password: zod__default.string().optional().describe("Password for Pact Broker")
16
+ ).optional()
16
17
  });
17
18
  class PactflowClient {
18
19
  name = "Contract Testing";
19
20
  capabilityPrefix = "contract-testing";
20
21
  configPrefix = "Pact-Broker";
21
22
  config = ConfigurationSchema;
22
- token;
23
- username;
24
- password;
23
+ authenticationFields = AuthenticationSchema;
25
24
  aiBaseUrl;
26
25
  baseUrl;
27
26
  _clientType;
@@ -32,7 +31,7 @@ class PactflowClient {
32
31
  return this._server;
33
32
  }
34
33
  /**
35
- * Initialises the client with auth credentials and the MCP server reference.
34
+ * Initializes the client with auth credentials and the MCP server reference.
36
35
  * Accepts either a Bearer token (PactFlow) or username/password (Pact Broker).
37
36
  * Does nothing if neither is supplied.
38
37
  *
@@ -40,23 +39,21 @@ class PactflowClient {
40
39
  * @param config - Connection config (base_url + token OR username/password).
41
40
  */
42
41
  async configure(server, config) {
43
- this.token = config.token;
44
- this.username = config.username;
45
- this.password = config.password;
46
- if (typeof config.token === "string") {
47
- this._clientType = "pactflow";
48
- } else if (typeof config.username === "string" && typeof config.password === "string") {
42
+ this._server = server;
43
+ if (this._server.getEnv("username", this) && this._server.getEnv("password", this)) {
49
44
  this._clientType = "pact_broker";
50
45
  } else {
51
46
  this._clientType = "pactflow";
52
47
  }
53
48
  this.baseUrl = config.base_url;
54
49
  this.aiBaseUrl = `${this.baseUrl}/api/ai`;
55
- this._server = server;
56
50
  }
57
51
  /** Returns true if the client has been configured with a base URL and credentials. */
58
52
  isConfigured() {
59
- return this.baseUrl !== void 0;
53
+ return !!this._server;
54
+ }
55
+ hasAuth() {
56
+ return this.isConfigured() && !!this.requestHeaders;
60
57
  }
61
58
  // PactFlow AI client methods
62
59
  /**
@@ -166,38 +163,28 @@ class PactflowClient {
166
163
  }
167
164
  /** Returns the current auth/content-type headers used for all requests. */
168
165
  get requestHeaders() {
169
- let contextToken = getRequestHeader("Pact-Token") || getRequestHeader("Authorization");
170
- if (Array.isArray(contextToken)) {
171
- contextToken = contextToken[0];
172
- }
173
- if (contextToken) {
174
- let authHeader = contextToken;
175
- if (!contextToken.startsWith("Basic ") && !contextToken.startsWith("Bearer ")) {
176
- authHeader = `Bearer ${contextToken}`;
166
+ const token = this.server?.getEnv("token", this) || this.server?.getEnv("Authorization");
167
+ if (token) {
168
+ let authHeader = token;
169
+ if (!token.startsWith("Basic ") && !token.startsWith("Bearer ")) {
170
+ authHeader = `Bearer ${token}`;
177
171
  }
178
172
  return {
179
173
  Authorization: authHeader,
180
174
  "Content-Type": "application/json",
181
175
  "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
182
176
  };
183
- }
184
- if (this.token) {
185
- let authHeader = this.token;
186
- if (!authHeader.startsWith("Basic ") && !authHeader.startsWith("Bearer ")) {
187
- authHeader = `Bearer ${authHeader}`;
177
+ } else {
178
+ const username = this.server?.getEnv("username", this);
179
+ const password = this.server?.getEnv("password", this);
180
+ if (username && password) {
181
+ const authString = `${username}:${password}`;
182
+ return {
183
+ Authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
184
+ "Content-Type": "application/json",
185
+ "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
186
+ };
188
187
  }
189
- return {
190
- Authorization: authHeader,
191
- "Content-Type": "application/json",
192
- "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
193
- };
194
- } else if (this.username && this.password) {
195
- const authString = `${this.username}:${this.password}`;
196
- return {
197
- Authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
198
- "Content-Type": "application/json",
199
- "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
200
- };
201
188
  }
202
189
  return void 0;
203
190
  }
@@ -4,6 +4,7 @@ const AUTOMATION_TOOLS = [
4
4
  {
5
5
  handler: QMetryToolsHandlers.IMPORT_AUTOMATION_RESULTS,
6
6
  title: "Import Automation Test Results",
7
+ toolset: "Automation",
7
8
  summary: "Import/Publish automation test results from TestNG, JUnit, Cucumber, Robot, HPUFT, or QAF frameworks into QMetry",
8
9
  purpose: "Upload and import automation test result files to create test suites, test cases, and execution records in QMetry",
9
10
  inputSchema: ImportAutomationResultsPayloadSchema,
@@ -269,6 +270,7 @@ const AUTOMATION_TOOLS = [
269
270
  {
270
271
  handler: QMetryToolsHandlers.FETCH_AUTOMATION_STATUS,
271
272
  title: "Fetch Automation Status",
273
+ toolset: "Automation",
272
274
  summary: "Fetches the status of an automation import job by request ID.",
273
275
  purpose: "Track the progress and result of an automation import operation in QMetry.",
274
276
  inputSchema: FetchAutomationStatusPayloadSchema,
@@ -3,6 +3,7 @@ import { CreateIssueArgsSchema, UpdateIssueArgsSchema, IssuesListArgsSchema, Lin
3
3
  const ISSUE_TOOLS = [
4
4
  {
5
5
  title: "Create Defect or Issue",
6
+ toolset: "Issues",
6
7
  summary: "Create a new defect/issue internally in QMetry.",
7
8
  handler: QMetryToolsHandlers.CREATE_ISSUE,
8
9
  inputSchema: CreateIssueArgsSchema,
@@ -120,6 +121,7 @@ const ISSUE_TOOLS = [
120
121
  },
121
122
  {
122
123
  title: "Update Issue",
124
+ toolset: "Issues",
123
125
  summary: "Update an existing QMetry issue by DefectId and/or entityKey.",
124
126
  handler: QMetryToolsHandlers.UPDATE_ISSUE,
125
127
  inputSchema: UpdateIssueArgsSchema,
@@ -170,6 +172,7 @@ const ISSUE_TOOLS = [
170
172
  },
171
173
  {
172
174
  title: "Fetch Defects or Issues",
175
+ toolset: "Issues",
173
176
  summary: "Fetch QMetry defects or issues - automatically handles viewId resolution based on project",
174
177
  handler: QMetryToolsHandlers.FETCH_ISSUES,
175
178
  inputSchema: IssuesListArgsSchema,
@@ -274,6 +277,7 @@ const ISSUE_TOOLS = [
274
277
  },
275
278
  {
276
279
  title: "Fetch Linked Issues of Test Case Run",
280
+ toolset: "Issues",
277
281
  summary: "Get issues that are linked (or not linked) to a specific test case run in QMetry",
278
282
  handler: QMetryToolsHandlers.FETCH_LINKED_ISSUES_BY_TESTCASE_RUN,
279
283
  inputSchema: LinkedIssuesByTestCaseRunArgsSchema,
@@ -403,6 +407,7 @@ const ISSUE_TOOLS = [
403
407
  },
404
408
  {
405
409
  title: "Link Issues to Testcase Run",
410
+ toolset: "Issues",
406
411
  summary: "Link one or more issues to a QMetry Testcase Run (execution).",
407
412
  handler: QMetryToolsHandlers.LINK_ISSUES_TO_TESTCASE_RUN,
408
413
  inputSchema: LinkIssuesToTestcaseRunArgsSchema,
@@ -438,6 +443,7 @@ const ISSUE_TOOLS = [
438
443
  },
439
444
  {
440
445
  title: "Fetch Issues Linked to Test Case",
446
+ toolset: "Issues",
441
447
  summary: "Get issues that are linked (or not linked) to a specific test case in QMetry",
442
448
  handler: QMetryToolsHandlers.FETCH_ISSUES_LINKED_TO_TESTCASE,
443
449
  inputSchema: IssuesLinkedToTestCaseArgsSchema,
@@ -3,6 +3,7 @@ import { ProjectListArgsSchema, ProjectArgsSchema, ReleasesCyclesArgsSchema, Bui
3
3
  const PROJECT_TOOLS = [
4
4
  {
5
5
  title: "Fetch QMetry list Projects",
6
+ toolset: "Projects",
6
7
  summary: "Fetch QMetry projects list including projectID, name, projectKey, isArchived, viewIds and folderPath needed for other operations",
7
8
  handler: QMetryToolsHandlers.FETCH_PROJECTS,
8
9
  inputSchema: ProjectListArgsSchema,
@@ -72,6 +73,7 @@ const PROJECT_TOOLS = [
72
73
  },
73
74
  {
74
75
  title: "Set QMetry Project Info",
76
+ toolset: "Projects",
75
77
  summary: "Set current QMetry project for your account",
76
78
  handler: QMetryToolsHandlers.SET_PROJECT_INFO,
77
79
  inputSchema: ProjectArgsSchema,
@@ -112,6 +114,7 @@ const PROJECT_TOOLS = [
112
114
  },
113
115
  {
114
116
  title: "Fetch QMetry Project Info",
117
+ toolset: "Projects",
115
118
  summary: "Fetch QMetry project information including viewId and folderPath needed for other operations",
116
119
  handler: QMetryToolsHandlers.FETCH_PROJECT_INFO,
117
120
  inputSchema: ProjectArgsSchema,
@@ -146,6 +149,7 @@ const PROJECT_TOOLS = [
146
149
  },
147
150
  {
148
151
  title: "Fetch Releases and Cycles",
152
+ toolset: "Projects",
149
153
  summary: "Fetch QMetry releases and cycles from the current project",
150
154
  handler: QMetryToolsHandlers.FETCH_RELEASES_CYCLES,
151
155
  inputSchema: ReleasesCyclesArgsSchema,
@@ -195,6 +199,7 @@ const PROJECT_TOOLS = [
195
199
  },
196
200
  {
197
201
  title: "Fetch Builds",
202
+ toolset: "Projects",
198
203
  summary: "Fetch QMetry builds from the current project",
199
204
  handler: QMetryToolsHandlers.FETCH_BUILDS,
200
205
  inputSchema: BuildArgsSchema,
@@ -252,6 +257,7 @@ const PROJECT_TOOLS = [
252
257
  },
253
258
  {
254
259
  title: "Fetch Platforms",
260
+ toolset: "Projects",
255
261
  summary: "Fetch QMetry platforms from the current project",
256
262
  handler: QMetryToolsHandlers.FETCH_PLATFORMS,
257
263
  inputSchema: PlatformArgsSchema,
@@ -332,6 +338,7 @@ const PROJECT_TOOLS = [
332
338
  },
333
339
  {
334
340
  title: "Create Release",
341
+ toolset: "Projects",
335
342
  summary: "Create a new release in QMetry with optional cycle for test planning and execution tracking",
336
343
  handler: QMetryToolsHandlers.CREATE_RELEASE,
337
344
  inputSchema: CreateReleaseArgsSchema,
@@ -423,6 +430,7 @@ const PROJECT_TOOLS = [
423
430
  },
424
431
  {
425
432
  title: "Create Cycle",
433
+ toolset: "Projects",
426
434
  summary: "Create a new cycle within an existing release in QMetry for test execution planning",
427
435
  handler: QMetryToolsHandlers.CREATE_CYCLE,
428
436
  inputSchema: CreateCycleArgsSchema,
@@ -538,6 +546,7 @@ const PROJECT_TOOLS = [
538
546
  },
539
547
  {
540
548
  title: "Update Cycle",
549
+ toolset: "Projects",
541
550
  summary: "Update an existing cycle in QMetry for test execution planning",
542
551
  handler: QMetryToolsHandlers.UPDATE_CYCLE,
543
552
  inputSchema: UpdateCycleArgsSchema,
@@ -3,6 +3,7 @@ import { RequirementListArgsSchema, RequirementDetailsArgsSchema, LinkRequiremen
3
3
  const REQUIREMENT_TOOLS = [
4
4
  {
5
5
  title: "Fetch Requirements",
6
+ toolset: "Requirements",
6
7
  summary: "Fetch QMetry requirements - automatically handles viewId resolution based on project",
7
8
  handler: QMetryToolsHandlers.FETCH_REQUIREMENTS,
8
9
  inputSchema: RequirementListArgsSchema,
@@ -178,6 +179,7 @@ const REQUIREMENT_TOOLS = [
178
179
  },
179
180
  {
180
181
  title: "Fetch Requirement Details",
182
+ toolset: "Requirements",
181
183
  summary: "Get detailed information for a specific QMetry requirement by numeric ID",
182
184
  handler: QMetryToolsHandlers.FETCH_REQUIREMENT_DETAILS,
183
185
  inputSchema: RequirementDetailsArgsSchema,
@@ -211,6 +213,7 @@ const REQUIREMENT_TOOLS = [
211
213
  },
212
214
  {
213
215
  title: "Link Requirements to Testcase",
216
+ toolset: "Requirements",
214
217
  summary: "Link one or more requirements to a test case by entityKey and version IDs.",
215
218
  handler: QMetryToolsHandlers.LINK_REQUIREMENT_TO_TESTCASE,
216
219
  inputSchema: LinkRequirementToTestCaseArgsSchema,
@@ -245,6 +248,7 @@ const REQUIREMENT_TOOLS = [
245
248
  },
246
249
  {
247
250
  title: "Fetch Test Cases Linked to Requirement",
251
+ toolset: "Requirements",
248
252
  summary: "Get test cases that are linked (or not linked) to a specific requirement in QMetry",
249
253
  handler: QMetryToolsHandlers.FETCH_TESTCASES_LINKED_TO_REQUIREMENT,
250
254
  inputSchema: TestCasesLinkedToRequirementArgsSchema,
@@ -408,6 +412,7 @@ const REQUIREMENT_TOOLS = [
408
412
  },
409
413
  {
410
414
  title: "Fetch Requirements Linked to Test Case",
415
+ toolset: "Requirements",
411
416
  summary: "Get requirements that are linked (or not linked) to a specific test case in QMetry",
412
417
  handler: QMetryToolsHandlers.FETCH_REQUIREMENTS_LINKED_TO_TESTCASE,
413
418
  inputSchema: RequirementsLinkedToTestCaseArgsSchema,
@@ -3,6 +3,7 @@ import { CreateTestCaseArgsSchema, UpdateTestCaseArgsSchema, TestCaseListArgsSch
3
3
  const TESTCASE_TOOLS = [
4
4
  {
5
5
  title: "Create Test Case",
6
+ toolset: "Test Cases",
6
7
  summary: "Create a new test case in QMetry with steps, metadata, and release/cycle mapping.",
7
8
  handler: QMetryToolsHandlers.CREATE_TEST_CASE,
8
9
  inputSchema: CreateTestCaseArgsSchema,
@@ -106,6 +107,7 @@ const TESTCASE_TOOLS = [
106
107
  },
107
108
  {
108
109
  title: "Update Test Case",
110
+ toolset: "Test Cases",
109
111
  summary: "Update an existing QMetry test case OR create a new version by tcID and tcVersionID, with auto-resolution from entityKey.",
110
112
  handler: QMetryToolsHandlers.UPDATE_TEST_CASE,
111
113
  inputSchema: UpdateTestCaseArgsSchema,
@@ -722,6 +724,7 @@ const TESTCASE_TOOLS = [
722
724
  },
723
725
  {
724
726
  title: "Fetch Test Cases",
727
+ toolset: "Test Cases",
725
728
  summary: "Fetch QMetry test cases - automatically handles viewId resolution based on project",
726
729
  handler: QMetryToolsHandlers.FETCH_TEST_CASES,
727
730
  inputSchema: TestCaseListArgsSchema,
@@ -843,6 +846,7 @@ const TESTCASE_TOOLS = [
843
846
  },
844
847
  {
845
848
  title: "Fetch Test Case Details",
849
+ toolset: "Test Cases",
846
850
  summary: "Get detailed information for a specific QMetry test case by numeric ID - USE THIS for single test case lookup",
847
851
  handler: QMetryToolsHandlers.FETCH_TEST_CASE_DETAILS,
848
852
  inputSchema: TestCaseDetailsArgsSchema,
@@ -879,6 +883,7 @@ const TESTCASE_TOOLS = [
879
883
  },
880
884
  {
881
885
  title: "Fetch Test Case Version Details",
886
+ toolset: "Test Cases",
882
887
  summary: "Get QMetry test case details for a specific version by numeric ID",
883
888
  handler: QMetryToolsHandlers.FETCH_TEST_CASE_VERSION_DETAILS,
884
889
  inputSchema: TestCaseVersionDetailsArgsSchema,
@@ -908,6 +913,7 @@ const TESTCASE_TOOLS = [
908
913
  },
909
914
  {
910
915
  title: "Fetch Test Case Steps",
916
+ toolset: "Test Cases",
911
917
  summary: "Get detailed test case steps for a specific test case by numeric ID",
912
918
  handler: QMetryToolsHandlers.FETCH_TEST_CASE_STEPS,
913
919
  inputSchema: TestCaseStepsArgsSchema,
@@ -937,6 +943,7 @@ const TESTCASE_TOOLS = [
937
943
  },
938
944
  {
939
945
  title: "Fetch Test Case Executions",
946
+ toolset: "Test Cases",
940
947
  summary: "Get execution records for a specific test case by numeric ID",
941
948
  handler: QMetryToolsHandlers.FETCH_TEST_CASE_EXECUTIONS,
942
949
  inputSchema: TestCaseExecutionsArgsSchema,
@@ -3,6 +3,7 @@ import { CreateTestSuiteArgsSchema, UpdateTestSuiteArgsSchema, TestSuiteListArgs
3
3
  const TESTSUITE_TOOLS = [
4
4
  {
5
5
  title: "Create Test Suite",
6
+ toolset: "Test Suites",
6
7
  summary: "Create a new test suite in QMetry with metadata and release/cycle mapping.",
7
8
  handler: QMetryToolsHandlers.CREATE_TEST_SUITE,
8
9
  inputSchema: CreateTestSuiteArgsSchema,
@@ -78,6 +79,7 @@ const TESTSUITE_TOOLS = [
78
79
  },
79
80
  {
80
81
  title: "Update Test Suite",
82
+ toolset: "Test Suites",
81
83
  summary: "Update an existing QMetry test suite by id(testsuite numeric id), with auto-resolution from entityKey.",
82
84
  handler: QMetryToolsHandlers.UPDATE_TEST_SUITE,
83
85
  inputSchema: UpdateTestSuiteArgsSchema,
@@ -139,6 +141,7 @@ const TESTSUITE_TOOLS = [
139
141
  },
140
142
  {
141
143
  title: "Fetch Test Suites",
144
+ toolset: "Test Suites",
142
145
  summary: "Fetch QMetry test suites - automatically handles viewId resolution based on project",
143
146
  handler: QMetryToolsHandlers.FETCH_TEST_SUITES,
144
147
  inputSchema: TestSuiteListArgsSchema,
@@ -244,6 +247,7 @@ const TESTSUITE_TOOLS = [
244
247
  },
245
248
  {
246
249
  title: "Fetch Test Suites for Test Case",
250
+ toolset: "Test Suites",
247
251
  summary: "Get test suites that can be linked to test cases in QMetry with automatic viewId resolution",
248
252
  handler: QMetryToolsHandlers.FETCH_TESTSUITES_FOR_TESTCASE,
249
253
  inputSchema: TestSuitesForTestCaseArgsSchema,
@@ -349,6 +353,7 @@ const TESTSUITE_TOOLS = [
349
353
  },
350
354
  {
351
355
  title: "Link Test Cases to Test Suite",
356
+ toolset: "Test Suites",
352
357
  summary: "Link test cases to a test suite in QMetry.",
353
358
  handler: QMetryToolsHandlers.LINK_TESTCASES_TO_TESTSUITE,
354
359
  inputSchema: LinkTestCasesToTestSuiteArgsSchema,
@@ -398,6 +403,7 @@ const TESTSUITE_TOOLS = [
398
403
  },
399
404
  {
400
405
  title: "Requirements Linked Test Cases to Test Suite",
406
+ toolset: "Test Suites",
401
407
  summary: "Link test cases (including those linked to requirements) to a test suite in QMetry.",
402
408
  handler: QMetryToolsHandlers.REQUIREMENTS_LINKED_TESTCASES_TO_TESTSUITE,
403
409
  inputSchema: RequirementsLinkedTestCasesToTestSuiteArgsSchema,
@@ -443,6 +449,7 @@ const TESTSUITE_TOOLS = [
443
449
  },
444
450
  {
445
451
  title: "Link Platforms to Test Suite",
452
+ toolset: "Test Suites",
446
453
  summary: "Link one or more platforms to a QMetry Test Suite.",
447
454
  handler: QMetryToolsHandlers.LINK_PLATFORMS_TO_TESTSUITE,
448
455
  inputSchema: LinkPlatformsToTestSuiteArgsSchema,
@@ -496,6 +503,7 @@ const TESTSUITE_TOOLS = [
496
503
  },
497
504
  {
498
505
  title: "Fetch Test Cases Linked to Test Suite",
506
+ toolset: "Test Suites",
499
507
  summary: "Get test cases that are linked (or not linked) to a specific test suite in QMetry",
500
508
  handler: QMetryToolsHandlers.FETCH_TESTCASES_BY_TESTSUITE,
501
509
  inputSchema: TestCasesByTestSuiteArgsSchema,
@@ -581,6 +589,7 @@ const TESTSUITE_TOOLS = [
581
589
  },
582
590
  {
583
591
  title: "Fetch Executions by Test Suite",
592
+ toolset: "Test Suites",
584
593
  summary: "Get executions for a given test suite in QMetry",
585
594
  handler: QMetryToolsHandlers.FETCH_EXECUTIONS_BY_TESTSUITE,
586
595
  inputSchema: ExecutionsByTestSuiteArgsSchema,
@@ -693,6 +702,7 @@ const TESTSUITE_TOOLS = [
693
702
  },
694
703
  {
695
704
  title: "Fetch Test Case Runs by Test Suite Run",
705
+ toolset: "Test Suites",
696
706
  summary: "Get test case runs under a specific test suite run execution in QMetry",
697
707
  handler: QMetryToolsHandlers.FETCH_TESTCASE_RUNS_BY_TESTSUITE_RUN,
698
708
  inputSchema: TestCaseRunsByTestSuiteRunArgsSchema,
@@ -845,6 +855,7 @@ const TESTSUITE_TOOLS = [
845
855
  },
846
856
  {
847
857
  title: "Bulk Update Test Case Execution Status",
858
+ toolset: "Test Suites",
848
859
  summary: "Update execution status for individual or multiple test case runs in bulk",
849
860
  handler: QMetryToolsHandlers.BULK_UPDATE_EXECUTION_STATUS,
850
861
  inputSchema: BulkUpdateExecutionStatusArgsSchema,
@@ -1,43 +1,45 @@
1
1
  import zod__default from "zod";
2
- import { getRequestHeader } from "../common/request-context.js";
3
2
  import { findAutoResolveConfig, autoResolveViewIdAndFolderPath } from "./client/auto-resolve.js";
4
3
  import { QMETRY_HANDLER_MAP } from "./client/handlers.js";
5
4
  import { getProjectInfo } from "./client/project.js";
6
5
  import { TOOLS } from "./client/tools/index.js";
7
6
  import { QMETRY_DEFAULTS } from "./config/constants.js";
8
7
  const ConfigurationSchema = zod__default.object({
9
- api_key: zod__default.string().describe("QMetry API key for authentication"),
10
8
  base_url: zod__default.string().url().optional().describe(
11
9
  "Optional QMetry base URL for custom or region-specific endpoints"
12
10
  )
13
11
  });
12
+ const AuthenticationSchema = zod__default.object({
13
+ api_key: zod__default.string().describe("QMetry API key for authentication").optional()
14
+ });
14
15
  class QmetryClient {
15
16
  name = "QMetry";
16
17
  capabilityPrefix = "qmetry";
17
18
  configPrefix = "Qmetry";
18
19
  config = ConfigurationSchema;
19
- token;
20
+ authenticationFields = AuthenticationSchema;
20
21
  projectApiKey = QMETRY_DEFAULTS.PROJECT_KEY;
21
22
  endpoint = QMETRY_DEFAULTS.BASE_URL;
22
- async configure(_server, config, _cache) {
23
- this.token = config.api_key;
23
+ server;
24
+ async configure(server, config) {
25
+ this.server = server;
24
26
  if (config.base_url) {
25
27
  this.endpoint = config.base_url;
26
28
  }
27
29
  }
28
30
  isConfigured() {
29
- return true;
31
+ return !!this.server;
30
32
  }
31
- getToken() {
32
- let contextToken = getRequestHeader("Qmetry-Token") || getRequestHeader("apikey");
33
- if (Array.isArray(contextToken)) {
34
- contextToken = contextToken[0];
35
- }
36
- if (contextToken) {
37
- return contextToken;
38
- }
39
- if (!this.token) throw new Error("Client not configured");
40
- return this.token;
33
+ hasAuth() {
34
+ return this.isConfigured() && !!this.getAuthToken();
35
+ }
36
+ getAuthToken() {
37
+ return this.server?.getEnv("api_key", this);
38
+ }
39
+ getAuthTokenOrThrow() {
40
+ const token = this.getAuthToken();
41
+ if (!token) throw new Error("Client not configured");
42
+ return token;
41
43
  }
42
44
  getBaseUrl() {
43
45
  return this.endpoint;
@@ -84,7 +86,7 @@ class QmetryClient {
84
86
  let projectInfo;
85
87
  try {
86
88
  projectInfo = await getProjectInfo(
87
- this.getToken(),
89
+ this.getAuthTokenOrThrow(),
88
90
  baseUrl,
89
91
  projectKey
90
92
  );
@@ -105,7 +107,7 @@ class QmetryClient {
105
107
  }
106
108
  const { projectKey: _, baseUrl: __, ...cleanArgs } = a;
107
109
  const result = await handlerFn(
108
- this.getToken(),
110
+ this.getAuthTokenOrThrow(),
109
111
  baseUrl,
110
112
  projectKey,
111
113
  cleanArgs
@@ -1,18 +1,21 @@
1
1
  import zod__default from "zod";
2
- import { getRequestHeader } from "../common/request-context.js";
3
2
  import { CONFIG_KEYS, API_CONFIG, SCHEMA_DESCRIPTIONS, CLIENT_CONFIG, ERROR_MESSAGES } from "./config/constants.js";
4
3
  import { ApiClient } from "./http/api-client.js";
5
4
  import { ResolverRegistry } from "./resolver/resolver-registry.js";
6
5
  const ConfigurationSchema = zod__default.object({
7
- [CONFIG_KEYS.API_KEY]: zod__default.string().describe(SCHEMA_DESCRIPTIONS.API_KEY),
8
6
  [CONFIG_KEYS.BASE_URL]: zod__default.string().url().optional().default(API_CONFIG.DEFAULT_BASE_URL).describe(SCHEMA_DESCRIPTIONS.BASE_URL)
9
7
  });
8
+ const AuthenticationSchema = zod__default.object({
9
+ api_key: zod__default.string().describe(SCHEMA_DESCRIPTIONS.API_KEY).optional(),
10
+ automation_api_key: zod__default.string().describe(SCHEMA_DESCRIPTIONS.AUTOMATION_API_KEY).optional()
11
+ });
10
12
  class Qtm4jClient {
11
13
  name = CLIENT_CONFIG.NAME;
12
14
  capabilityPrefix = CLIENT_CONFIG.TOOL_PREFIX;
13
15
  configPrefix = CLIENT_CONFIG.CONFIG_PREFIX;
14
16
  config = ConfigurationSchema;
15
- _apiKey;
17
+ authenticationFields = AuthenticationSchema;
18
+ server;
16
19
  baseUrl = API_CONFIG.DEFAULT_BASE_URL;
17
20
  apiClient;
18
21
  resolverRegistry;
@@ -22,38 +25,35 @@ class Qtm4jClient {
22
25
  * @param config - Configuration object containing API key and optional base URL
23
26
  */
24
27
  async configure(server, config) {
25
- this._apiKey = config[CONFIG_KEYS.API_KEY];
28
+ this.server = server;
26
29
  if (config[CONFIG_KEYS.BASE_URL]) {
27
30
  this.baseUrl = config[CONFIG_KEYS.BASE_URL];
28
31
  }
29
- this.apiClient = new ApiClient(() => this.getAuthToken(), this.baseUrl);
32
+ this.apiClient = new ApiClient(
33
+ () => this.getAuthToken(),
34
+ this.baseUrl,
35
+ () => this.getAutomationApiKey()
36
+ );
30
37
  this.resolverRegistry = new ResolverRegistry(
31
38
  this.apiClient,
32
39
  server.getCache()
33
40
  );
34
41
  }
35
- /**
36
- * Get authentication token with request-scoped override support
37
- * Checks request headers first, then falls back to configured API key
38
- * @returns API key or null if not found
39
- */
40
- getAuthToken() {
41
- const contextHeader = getRequestHeader("Qtm4j-Api-Key") || getRequestHeader("apiKey") || getRequestHeader("Authorization");
42
- if (contextHeader) {
43
- let token = Array.isArray(contextHeader) ? contextHeader[0] : contextHeader;
44
- if (token.startsWith("Bearer ")) {
45
- token = token.substring(7);
46
- }
47
- return token;
48
- }
49
- return this._apiKey || null;
50
- }
51
42
  /**
52
43
  * Check if the client is properly configured
53
44
  * @returns true if API key is set and client is ready
54
45
  */
55
46
  isConfigured() {
56
- return this.apiClient !== void 0;
47
+ return !!this.apiClient;
48
+ }
49
+ hasAuth() {
50
+ return this.isConfigured() && !!this.getAuthToken();
51
+ }
52
+ getAuthToken() {
53
+ return this.server?.getEnv(CONFIG_KEYS.API_KEY, this) || this.server?.getEnv("Authorization") || null;
54
+ }
55
+ getAutomationApiKey() {
56
+ return this.server?.getEnv(CONFIG_KEYS.AUTOMATION_API_KEY, this) || null;
57
57
  }
58
58
  /**
59
59
  * Get the configured API client instance
@@ -91,13 +91,47 @@ class Qtm4jClient {
91
91
  const { GetTestCases } = await import("./tool/test-case/get-test-cases.js");
92
92
  const { GetTestSteps } = await import("./tool/test-case/get-test-steps.js");
93
93
  const { UpdateTestCase } = await import("./tool/test-case/update-test-case.js");
94
+ const { UploadAutomationResult } = await import("./tool/test-automation/upload-automation-result.js");
95
+ const { GetAutomationHistory } = await import("./tool/test-automation/get-automation-history.js");
96
+ const { CreateTestCycle } = await import("./tool/test-cycle/create-test-cycle.js");
97
+ const { SearchTestCycles } = await import("./tool/test-cycle/search-test-cycle.js");
98
+ const { UpdateTestCycle } = await import("./tool/test-cycle/update-test-cycle.js");
99
+ const { LinkRequirements } = await import("./tool/test-case/link-requirements.js");
100
+ const { UnlinkRequirements } = await import("./tool/test-case/unlink-requirements.js");
101
+ const { LinkTestCasesToRequirement } = await import("./tool/requirement/link-testcases.js");
102
+ const { UnlinkTestCasesFromRequirement } = await import("./tool/requirement/unlink-testcases.js");
103
+ const { GetLinkedRequirements } = await import("./tool/test-case/get-linked-requirements.js");
104
+ const { GetLinkedTestCasesForRequirement } = await import("./tool/requirement/get-linked-testcases.js");
105
+ const { LinkTestCasesToCycle } = await import("./tool/test-cycle/link-testcases.js");
106
+ const { UnlinkTestCasesFromCycle } = await import("./tool/test-cycle/unlink-testcases.js");
107
+ const { SearchLinkedTestCasesInCycle } = await import("./tool/test-cycle/search-linked-testcases.js");
108
+ const { LinkRequirementsToCycle } = await import("./tool/test-cycle/link-requirements.js");
109
+ const { UnlinkRequirementsFromCycle } = await import("./tool/test-cycle/unlink-requirements.js");
110
+ const { GetLinkedRequirementsForCycle } = await import("./tool/test-cycle/get-linked-requirements.js");
94
111
  const tools = [
95
112
  new GetProjects(this),
96
113
  new SetProjectContext(this),
97
114
  new CreateTestCase(this),
98
115
  new GetTestCases(this),
99
116
  new GetTestSteps(this),
100
- new UpdateTestCase(this)
117
+ new UpdateTestCase(this),
118
+ new CreateTestCycle(this),
119
+ new SearchTestCycles(this),
120
+ new UpdateTestCycle(this),
121
+ new UploadAutomationResult(this),
122
+ new GetAutomationHistory(this),
123
+ new LinkRequirements(this),
124
+ new UnlinkRequirements(this),
125
+ new LinkTestCasesToRequirement(this),
126
+ new UnlinkTestCasesFromRequirement(this),
127
+ new GetLinkedRequirements(this),
128
+ new GetLinkedTestCasesForRequirement(this),
129
+ new LinkTestCasesToCycle(this),
130
+ new UnlinkTestCasesFromCycle(this),
131
+ new SearchLinkedTestCasesInCycle(this),
132
+ new LinkRequirementsToCycle(this),
133
+ new UnlinkRequirementsFromCycle(this),
134
+ new GetLinkedRequirementsForCycle(this)
101
135
  ];
102
136
  for (const tool of tools) {
103
137
  register(tool.specification, tool.handle);