@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
package/README.md CHANGED
@@ -107,7 +107,8 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
107
107
  "COLLABORATOR_USERNAME": "${input:collab_username}",
108
108
  "COLLABORATOR_LOGIN_TICKET": "${input:collab_login_ticket}",
109
109
  "QTM4J_API_KEY": "${input:qtm4j_api_key}",
110
- "QTM4J_BASE_URL": "${input:qtm4j_base_url}"
110
+ "QTM4J_BASE_URL": "${input:qtm4j_base_url}",
111
+ "QTM4J_AUTOMATION_API_KEY": "${input:qtm4j_automation_api_key}"
111
112
  }
112
113
  }
113
114
  },
@@ -243,6 +244,12 @@ Alternatively, you can use `npx` (or globally install) the `@smartbear/mcp` pack
243
244
  "type": "promptString",
244
245
  "description": "US region (default): https://qtmcloud.qmetry.com. Australia region: https://syd-qtmcloud.qmetry.com.",
245
246
  "password": false
247
+ },
248
+ {
249
+ "id": "qtm4j_automation_api_key",
250
+ "type": "promptString",
251
+ "description": "QTM4J Automation API Key - required for automation tools, leave blank to disable them",
252
+ "password": true
246
253
  }
247
254
  ]
248
255
  }
@@ -283,7 +290,8 @@ Add the following configuration to your `claude_desktop_config.json` to launch t
283
290
  "COLLABORATOR_USERNAME": "your collab user name",
284
291
  "COLLABORATOR_LOGIN_TICKET": "your collab login ticket",
285
292
  "QTM4J_API_KEY": "your_qtm4j_key",
286
- "QTM4J_BASE_URL": "https://qtmcloud.qmetry.com"
293
+ "QTM4J_BASE_URL": "https://qtmcloud.qmetry.com",
294
+ "QTM4J_AUTOMATION_API_KEY": "your_qtm4j_automation_api_key"
287
295
  }
288
296
  }
289
297
  }
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
3
- import { getRequestHeader } from "../common/request-context.js";
4
3
  import { ToolError } from "../common/tools.js";
5
4
  import { DEFAULT_API_BASE_URL, AUTHORIZATION_HEADER } from "./config/constants.js";
6
5
  import { ChatWithQaLead } from "./tool/tasks/chat-with-qa-lead.js";
@@ -16,33 +15,33 @@ import { RunTestsInFunctionalAreas } from "./tool/tasks/run-tests-in-functional-
16
15
  import { StopTask } from "./tool/tasks/stop-task.js";
17
16
  import { WaitForTask } from "./tool/tasks/wait-for-task.js";
18
17
  const ConfigurationSchema = z.object({
19
- api_token: z.string().describe("BearQ workspace API token (Bearer)."),
20
18
  api_base_url: z.string().optional().describe(
21
19
  "Override the BearQ public API base URL. Defaults to https://api.bearq.smartbear.com"
22
20
  )
23
21
  });
22
+ const AuthenticationSchema = z.object({
23
+ api_token: z.string().describe("BearQ workspace API token (Bearer).")
24
+ });
24
25
  class BearQClient {
25
- _apiToken;
26
+ server;
26
27
  _baseUrl = DEFAULT_API_BASE_URL;
27
28
  name = "BearQ";
28
29
  capabilityPrefix = "bearq";
29
30
  configPrefix = "BearQ";
30
31
  config = ConfigurationSchema;
31
- async configure(_server, config) {
32
- this._apiToken = config.api_token;
32
+ authenticationFields = AuthenticationSchema;
33
+ async configure(server, config) {
34
+ this.server = server;
33
35
  if (config.api_base_url) this._baseUrl = config.api_base_url;
34
36
  }
35
37
  getAuthToken() {
36
- const contextHeader = getRequestHeader(AUTHORIZATION_HEADER);
37
- if (contextHeader) {
38
- let token = Array.isArray(contextHeader) ? contextHeader[0] : contextHeader;
39
- if (token.startsWith("Bearer ")) token = token.substring(7);
40
- return token;
41
- }
42
- return this._apiToken ?? null;
38
+ return this.server?.getEnv("api_token", this) || this.server?.getEnv(AUTHORIZATION_HEADER) || null;
43
39
  }
44
40
  isConfigured() {
45
- return true;
41
+ return this.server !== void 0;
42
+ }
43
+ hasAuth() {
44
+ return this.isConfigured() && !!this.getAuthToken();
46
45
  }
47
46
  getBaseUrl() {
48
47
  return this._baseUrl;
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class ChatWithQaLead extends Tool {
9
9
  specification = {
10
10
  title: "Chat with QA Lead",
11
+ toolset: "Tasks",
11
12
  summary: "Sends an open-ended instruction to BearQ's QA lead agent. Use this when no other BearQ tool fits — the QA lead can list, create, and update test cases, manage functional areas, and read the application model, and acts as a general-purpose escape hatch.",
12
13
  inputSchema
13
14
  };
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class ExpandApplicationModel extends Tool {
9
9
  specification = {
10
10
  title: "Expand Application Model",
11
+ toolset: "Tasks",
11
12
  summary: "Explores the live application to discover or update its pages and elements in BearQ's application model. Optionally scope to a single functional area.",
12
13
  inputSchema
13
14
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class GetTaskStatus extends Tool {
7
7
  specification = {
8
8
  title: "Get Task Status",
9
+ toolset: "Tasks",
9
10
  summary: "Retrieves the status of a task (running / complete / error / cancelled). Cheaper than fetching full task details.",
10
11
  inputSchema
11
12
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class GetTask extends Tool {
7
7
  specification = {
8
8
  title: "Get Task",
9
+ toolset: "Tasks",
9
10
  summary: "Retrieves a task's current state, metadata, and activity log. Returns immediately with whatever's available — does not block on the task completing.",
10
11
  inputSchema
11
12
  };
@@ -4,6 +4,7 @@ const inputSchema = z.object({});
4
4
  class RefineAllDraftTests extends Tool {
5
5
  specification = {
6
6
  title: "Refine All Draft Tests",
7
+ toolset: "Tasks",
7
8
  summary: "Refines every draft test case in the workspace. Use to push an entire draft backlog forward; may take multiple passes before all drafts are ready to be promoted to regression tests.",
8
9
  inputSchema
9
10
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class RefineTestCases extends Tool {
7
7
  specification = {
8
8
  title: "Refine Test Cases",
9
+ toolset: "Tasks",
9
10
  summary: "Refines specific BearQ draft test cases — improves their steps so they can eventually be promoted to regression tests. Use when a draft is incomplete or has drifted from its intent.",
10
11
  inputSchema
11
12
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class RefineTestsInFunctionalAreas extends Tool {
7
7
  specification = {
8
8
  title: "Refine Tests in Functional Areas",
9
+ toolset: "Tasks",
9
10
  summary: "Refines every draft test case tagged with one or more functional areas. Functional areas can be given by ID or name. May take multiple passes before drafts are ready to be promoted to regression tests.",
10
11
  inputSchema
11
12
  };
@@ -4,6 +4,7 @@ const inputSchema = z.object({});
4
4
  class RunRegressionTests extends Tool {
5
5
  specification = {
6
6
  title: "Run Regression Tests",
7
+ toolset: "Tasks",
7
8
  summary: "Runs the full BearQ regression suite — every regression-ready test case in the workspace. Use for CI/CD or pre-release smoke.",
8
9
  inputSchema
9
10
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class RunTestCases extends Tool {
7
7
  specification = {
8
8
  title: "Run Test Cases",
9
+ toolset: "Tasks",
9
10
  summary: "Runs specific BearQ regression test cases by ID. Targets only regression-ready cases — drafts will be rejected.",
10
11
  inputSchema
11
12
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class RunTestsInFunctionalAreas extends Tool {
7
7
  specification = {
8
8
  title: "Run Tests in Functional Areas",
9
+ toolset: "Tasks",
9
10
  summary: "Runs every regression test case tagged with one or more functional areas. Functional areas can be given by ID or name.",
10
11
  inputSchema
11
12
  };
@@ -6,6 +6,7 @@ const inputSchema = z.object({
6
6
  class StopTask extends Tool {
7
7
  specification = {
8
8
  title: "Stop Task",
9
+ toolset: "Tasks",
9
10
  summary: "Cancels a running task.",
10
11
  inputSchema
11
12
  };
@@ -17,6 +17,7 @@ function parseFrame(frame) {
17
17
  class WaitForTask extends Tool {
18
18
  specification = {
19
19
  title: "Wait For Task",
20
+ toolset: "Tasks",
20
21
  summary: "Blocks until a BearQ task reaches a terminal state (completed / failed / cancelled) or the stream times out, then returns the full ordered sequence of SSE events from the public API (metadata, activityLogEntries, and a terminal done or timeout event) verbatim. Blocks for the lifetime of the task — for a quick check use bearq_get_task_status instead.",
21
22
  inputSchema
22
23
  };
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "../common/info.js";
3
- import { getRequestHeader } from "../common/request-context.js";
4
3
  import { ToolError } from "../common/tools.js";
5
4
  import { CurrentUserAPI } from "./client/api/CurrentUser.js";
6
5
  import { Configuration } from "./client/api/configuration.js";
@@ -40,11 +39,14 @@ const EXCLUDED_EVENT_FIELDS = /* @__PURE__ */ new Set([
40
39
  // This is searches multiple fields and is more a convenience for humans, we're removing to avoid over-matching
41
40
  ]);
42
41
  const ConfigurationSchema = z.object({
43
- auth_token: z.string().describe("BugSnag personal access token"),
44
42
  project_api_key: z.string().describe("BugSnag project API key").optional(),
45
- endpoint: z.string().url().describe("BugSnag endpoint URL").optional()
43
+ endpoint: z.url().describe("BugSnag endpoint URL").optional()
44
+ });
45
+ const AuthenticationSchema = z.object({
46
+ auth_token: z.string().describe("BugSnag personal access token").optional()
46
47
  });
47
48
  class BugsnagClient {
49
+ server;
48
50
  cache;
49
51
  _projectApiKey;
50
52
  _isConfigured = false;
@@ -52,7 +54,7 @@ class BugsnagClient {
52
54
  _errorsApi;
53
55
  _projectApi;
54
56
  _appEndpoint;
55
- _authToken;
57
+ apiConfig;
56
58
  get currentUserApi() {
57
59
  if (!this._currentUserApi) throw new Error("Client not configured");
58
60
  return this._currentUserApi;
@@ -73,7 +75,10 @@ class BugsnagClient {
73
75
  capabilityPrefix = "bugsnag";
74
76
  configPrefix = "Bugsnag";
75
77
  config = ConfigurationSchema;
78
+ defaultToolsets = ["Projects"];
79
+ authenticationFields = AuthenticationSchema;
76
80
  async configure(server, config) {
81
+ this.server = server;
77
82
  this.cache = server.getCache();
78
83
  this._appEndpoint = this.getEndpoint(
79
84
  "app",
@@ -81,45 +86,17 @@ class BugsnagClient {
81
86
  config.endpoint
82
87
  );
83
88
  this._projectApiKey = config.project_api_key;
84
- this._authToken = config.auth_token;
85
- await this.initializeApis(config);
86
- }
87
- getAuthToken() {
88
- const contextHeader = getRequestHeader("Bugsnag-Auth-Token");
89
- if (contextHeader) {
90
- let token = Array.isArray(contextHeader) ? contextHeader[0] : contextHeader;
91
- if (token.startsWith("token ")) {
92
- token = token.substring(6);
93
- }
94
- return `token ${token}`;
95
- }
96
- const bearerToken = this.getBearerToken();
97
- if (bearerToken) {
98
- return bearerToken;
99
- }
100
- return this._authToken ? `token ${this._authToken}` : null;
101
- }
102
- getBearerToken() {
103
- const contextHeader = getRequestHeader("Authorization");
104
- if (contextHeader) {
105
- let token = Array.isArray(contextHeader) ? contextHeader[0] : contextHeader;
106
- if (token.startsWith("Bearer ")) {
107
- token = token.substring(7);
108
- }
109
- return `Bearer ${token}`;
110
- }
111
- return null;
112
- }
113
- async initializeApis(config) {
114
- const apiConfig = new Configuration({
115
- apiKey: (_name) => {
116
- const authToken = this.getAuthToken();
89
+ this.apiConfig = new Configuration({
90
+ apiKey: () => {
91
+ const authToken = this.server?.getEnv("auth_token", this);
117
92
  if (authToken) {
118
- return authToken;
93
+ return `token ${authToken}`;
119
94
  }
120
- throw new Error(
121
- "Authentication token not found in request headers or configuration"
122
- );
95
+ const bearerToken = this.server?.getEnv("Authorization");
96
+ if (bearerToken) {
97
+ return `Bearer ${bearerToken}`;
98
+ }
99
+ return void 0;
123
100
  },
124
101
  headers: {
125
102
  "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
@@ -133,14 +110,17 @@ class BugsnagClient {
133
110
  config.endpoint
134
111
  )
135
112
  });
136
- this._currentUserApi = new CurrentUserAPI(apiConfig);
137
- this._errorsApi = new ErrorAPI(apiConfig);
138
- this._projectApi = new ProjectAPI(apiConfig);
113
+ this._currentUserApi = new CurrentUserAPI(this.apiConfig);
114
+ this._errorsApi = new ErrorAPI(this.apiConfig);
115
+ this._projectApi = new ProjectAPI(this.apiConfig);
139
116
  this._isConfigured = true;
140
117
  }
141
118
  isConfigured() {
142
119
  return this._isConfigured;
143
120
  }
121
+ hasAuth() {
122
+ return this.isConfigured() && !!this.apiConfig?.apiKey();
123
+ }
144
124
  // If the endpoint is not provided, it will use the default API endpoint based on the project API key.
145
125
  // if the project api key is not provided, the endpoint will be the default API endpoint.
146
126
  // if the endpoint is provided, it will be used as is for custom domains, or normalized for known domains.
@@ -14,6 +14,7 @@ const inputSchema = z.object({
14
14
  class GetError extends Tool {
15
15
  specification = {
16
16
  title: "Get Error",
17
+ toolset: "Errors",
17
18
  summary: "Get full details on an error, including aggregated and summarized data across all events (occurrences) and details of the latest event (occurrence), such as breadcrumbs, metadata and the stacktrace. Use the filters parameter to narrow down the summaries further.",
18
19
  purpose: "Retrieve all the information required on a specified error to understand who it is affecting and why.",
19
20
  useCases: [
@@ -14,6 +14,7 @@ const inputSchema = z.object({
14
14
  class ListProjectErrors extends Tool {
15
15
  specification = {
16
16
  title: "List Project Errors",
17
+ toolset: "Errors",
17
18
  summary: "List and search errors in a project using customizable filters and pagination",
18
19
  purpose: "Retrieve filtered list of errors from a project for analysis, debugging, and reporting",
19
20
  useCases: [
@@ -51,6 +51,7 @@ class UpdateError extends Tool {
51
51
  getInput;
52
52
  specification = {
53
53
  title: "Update Error",
54
+ toolset: "Errors",
54
55
  summary: "Update the status of an error",
55
56
  purpose: "Change an error's workflow state, such as marking it as resolved or ignored",
56
57
  useCases: [
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class GetEventDetailsFromDashboardUrl extends Tool {
9
9
  specification = {
10
10
  title: "Get Event Details From Dashboard URL",
11
+ toolset: "Events",
11
12
  summary: "Get detailed information about a specific event using its dashboard URL",
12
13
  purpose: "Retrieve event details directly from a dashboard URL for quick debugging",
13
14
  useCases: [
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class GetEvent extends Tool {
9
9
  specification = {
10
10
  title: "Get Event",
11
+ toolset: "Events",
11
12
  summary: "Get detailed information about a specific event",
12
13
  purpose: "Retrieve event details directly from its ID",
13
14
  useCases: [
@@ -14,6 +14,7 @@ const inputSchema = z.object({
14
14
  class ListErrorEvents extends Tool {
15
15
  specification = {
16
16
  title: "Get Events on an Error",
17
+ toolset: "Events",
17
18
  summary: "Gets a list of events that have grouped into the specified error",
18
19
  purpose: "Show the events that make up an error to see individual occurrences of the error for detailed analysis",
19
20
  useCases: [
@@ -7,6 +7,7 @@ const inputSchema = z.object({
7
7
  class GetNetworkEndpointGroupings extends Tool {
8
8
  specification = {
9
9
  title: "Get Network Endpoint Groupings",
10
+ toolset: "Performance",
10
11
  summary: "Get the network endpoint grouping rules for a project",
11
12
  purpose: "Retrieve the URL patterns used to group network spans for performance monitoring",
12
13
  useCases: [
@@ -9,6 +9,7 @@ const inputSchema = z.object({
9
9
  class GetSpanGroup extends Tool {
10
10
  specification = {
11
11
  title: "Get Span Group",
12
+ toolset: "Performance",
12
13
  summary: "Get detailed performance metrics for a specific span group",
13
14
  purpose: "Analyze performance characteristics of a specific operation",
14
15
  useCases: [
@@ -13,6 +13,7 @@ const inputSchema = z.object({
13
13
  class GetTrace extends Tool {
14
14
  specification = {
15
15
  title: "Get Trace",
16
+ toolset: "Performance",
16
17
  summary: "Get all spans within a specific trace",
17
18
  purpose: "View the complete trace of operations for a request/transaction",
18
19
  useCases: [
@@ -43,6 +43,7 @@ const inputSchema = z.object({
43
43
  class ListSpanGroups extends Tool {
44
44
  specification = {
45
45
  title: "List Span Groups",
46
+ toolset: "Performance",
46
47
  summary: "List span groups (operations) tracked for performance monitoring",
47
48
  purpose: "Discover and analyze different operations being monitored",
48
49
  useCases: [
@@ -29,6 +29,7 @@ const inputSchema = z.object({
29
29
  class ListSpans extends Tool {
30
30
  specification = {
31
31
  title: "List Spans",
32
+ toolset: "Performance",
32
33
  summary: "Get individual spans belonging to a span group",
33
34
  purpose: "Examine individual operation instances within a span group",
34
35
  useCases: [
@@ -7,6 +7,7 @@ const inputSchema = z.object({
7
7
  class ListTraceFields extends Tool {
8
8
  specification = {
9
9
  title: "List Trace Fields",
10
+ toolset: "Performance",
10
11
  summary: "Get available trace fields/attributes for filtering",
11
12
  purpose: "Discover what custom attributes are available for filtering",
12
13
  useCases: [
@@ -10,6 +10,7 @@ const inputSchema = z.object({
10
10
  class SetNetworkEndpointGroupings extends Tool {
11
11
  specification = {
12
12
  title: "Set Network Endpoint Groupings",
13
+ toolset: "Performance",
13
14
  summary: "Set the network endpoint grouping rules for a project",
14
15
  purpose: "Configure URL patterns to control how network spans are grouped in performance monitoring",
15
16
  useCases: [
@@ -3,6 +3,7 @@ import { toolInputParameters } from "../../input-schemas.js";
3
3
  class GetCurrentProject extends Tool {
4
4
  specification = {
5
5
  title: "Get Current Project",
6
+ toolset: "Projects",
6
7
  summary: "Retrieve the 'current' project on which tools should operate by default. This allows BugSnag tools to be called with no projectId parameter.",
7
8
  purpose: "Gets information about the 'current' BugSnag project, including ID and API key",
8
9
  useCases: ["Understand if a current project has been set"],
@@ -7,6 +7,7 @@ const inputSchema = z.object({
7
7
  class ListProjectEventFilters extends Tool {
8
8
  specification = {
9
9
  title: "List Project Event Filters",
10
+ toolset: "Projects",
10
11
  summary: "Get available event filter fields for a project",
11
12
  purpose: "Discover valid filter field names and options that can be used with the List Errors or Get Error tools",
12
13
  useCases: [
@@ -5,6 +5,7 @@ const inputSchema = z.object({
5
5
  });
6
6
  class ListProjects extends Tool {
7
7
  specification = {
8
+ toolset: "Projects",
8
9
  title: "List Projects",
9
10
  summary: "List all projects in the organization that the current user has access to, or find a project matching an API key.",
10
11
  purpose: "Retrieve available projects for browsing and selecting which project to analyze.",
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class GetBuild extends Tool {
9
9
  specification = {
10
10
  title: "Get Build",
11
+ toolset: "Releases",
11
12
  summary: "Get more details for a specific build by its ID",
12
13
  purpose: "Retrieve detailed information about a build for analysis and debugging",
13
14
  useCases: [
@@ -8,6 +8,7 @@ const inputSchema = z.object({
8
8
  class GetRelease extends Tool {
9
9
  specification = {
10
10
  title: "Get Release",
11
+ toolset: "Releases",
11
12
  summary: "Get more details for a specific release by its ID, including source control information and associated builds",
12
13
  purpose: "Retrieve detailed information about a release for analysis and debugging",
13
14
  useCases: [
@@ -13,6 +13,7 @@ const inputSchema = z.object({
13
13
  class ListReleases extends Tool {
14
14
  specification = {
15
15
  title: "List Releases",
16
+ toolset: "Releases",
16
17
  summary: "List releases for a project",
17
18
  purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
18
19
  useCases: [
@@ -1,26 +1,29 @@
1
1
  import { z } from "zod";
2
- import { getRequestHeader } from "../common/request-context.js";
3
2
  const ConfigurationSchema = z.object({
4
- base_url: z.url().describe("Collaborator server base URL"),
5
- username: z.string().describe("Collaborator username for authentication").optional(),
6
- login_ticket: z.string().describe("Collaborator login ticket for authentication").optional()
3
+ base_url: z.url().describe("Collaborator server base URL")
4
+ });
5
+ const AuthenticationSchema = z.object({
6
+ login: z.string().describe("Collaborator username for authentication").optional(),
7
+ ticket: z.string().describe("Collaborator login ticket for authentication").optional()
7
8
  });
8
9
  class CollaboratorClient {
9
10
  name = "Collaborator";
10
11
  capabilityPrefix = "collaborator";
11
12
  configPrefix = "Collaborator";
12
13
  config = ConfigurationSchema;
14
+ authenticationFields = AuthenticationSchema;
13
15
  baseUrl;
14
- username;
15
- loginTicket;
16
- async configure(_server, config, _cache) {
16
+ server;
17
+ async configure(server, config) {
17
18
  this.baseUrl = config.base_url;
18
- this.username = config.username;
19
- this.loginTicket = config.login_ticket;
19
+ this.server = server;
20
20
  }
21
21
  isConfigured() {
22
22
  return this.baseUrl !== void 0;
23
23
  }
24
+ hasAuth() {
25
+ return this.isConfigured() && this.server?.getEnv("Login", this) !== void 0 && this.server?.getEnv("Ticket", this) !== void 0;
26
+ }
24
27
  /**
25
28
  * Calls the Collaborator API with the given commands, prepending authentication automatically.
26
29
  * @param commands Array of Collaborator API commands (excluding authentication)
@@ -28,16 +31,8 @@ class CollaboratorClient {
28
31
  */
29
32
  async call(commands) {
30
33
  const url = `${this.baseUrl}/services/json/v1`;
31
- let login = this.username;
32
- let ticket = this.loginTicket;
33
- const contextLogin = getRequestHeader("Collaborator-Login");
34
- const contextTicket = getRequestHeader("Collaborator-Ticket");
35
- if (contextLogin) {
36
- login = Array.isArray(contextLogin) ? contextLogin[0] : contextLogin;
37
- }
38
- if (contextTicket) {
39
- ticket = Array.isArray(contextTicket) ? contextTicket[0] : contextTicket;
40
- }
34
+ const login = this.server?.getEnv("Login", this);
35
+ const ticket = this.server?.getEnv("Ticket", this);
41
36
  const body = [
42
37
  {
43
38
  command: "SessionService.authenticate",
@@ -64,6 +59,7 @@ class CollaboratorClient {
64
59
  register(
65
60
  {
66
61
  title: "Find Review By ID",
62
+ toolset: "Review Management",
67
63
  summary: "Finds a review in Collaborator by its review ID.",
68
64
  inputSchema: z.object({
69
65
  reviewId: z.string().describe("The Collaborator review ID to find.")
@@ -86,6 +82,7 @@ class CollaboratorClient {
86
82
  register(
87
83
  {
88
84
  title: "Create Review",
85
+ toolset: "Review Management",
89
86
  summary: "Creates a new review in Collaborator. All parameters are optional.",
90
87
  inputSchema: z.object({
91
88
  creator: z.string().optional().describe(
@@ -123,6 +120,7 @@ class CollaboratorClient {
123
120
  register(
124
121
  {
125
122
  title: "Reject Review",
123
+ toolset: "Review Management",
126
124
  summary: "Rejects a review in Collaborator by its review ID and reason.",
127
125
  inputSchema: z.object({
128
126
  reviewId: z.union([z.string(), z.number()]).describe("The Collaborator review ID to reject."),
@@ -149,6 +147,7 @@ class CollaboratorClient {
149
147
  register(
150
148
  {
151
149
  title: "ReviewService Action",
150
+ toolset: "Review Management",
152
151
  summary: "Invoke any ReviewService method by name and arguments. For finishReviewPhase and waitOnPhase, provide reviewId (required) and until (optional, defaults to 'ANY').",
153
152
  inputSchema: z.object({
154
153
  action: z.enum([
@@ -172,6 +171,7 @@ class CollaboratorClient {
172
171
  register(
173
172
  {
174
173
  title: "Get Reviews",
174
+ toolset: "Review Management",
175
175
  summary: "Retrieves reviews from Collaborator using ReviewService.getReviews. All parameters are optional and only provided ones are sent.",
176
176
  inputSchema: z.object({
177
177
  login: z.string().optional().describe("Collaborator username to filter reviews."),
@@ -208,6 +208,7 @@ class CollaboratorClient {
208
208
  register(
209
209
  {
210
210
  title: "Create Remote System Configuration",
211
+ toolset: "Remote System Configuration Management",
211
212
  summary: "Creates a remote system configuration in Collaborator (e.g., Bitbucket, GitHub, etc).",
212
213
  inputSchema: z.object({
213
214
  token: z.string().describe("Remote system token, e.g., BITBUCKET, GITHUB, etc."),
@@ -239,6 +240,7 @@ class CollaboratorClient {
239
240
  register(
240
241
  {
241
242
  title: "Edit Remote System Configuration",
243
+ toolset: "Remote System Configuration Management",
242
244
  summary: "Edits parameters of an existing remote system configuration in Collaborator. Only title and config are editable after creation.",
243
245
  inputSchema: z.object({
244
246
  id: z.string().describe("ID of the remote system Configuration to edit."),
@@ -272,6 +274,7 @@ class CollaboratorClient {
272
274
  register(
273
275
  {
274
276
  title: "Delete Remote System Configuration",
277
+ toolset: "Remote System Configuration Management",
275
278
  summary: "Deletes a remote system configuration in Collaborator by its ID.",
276
279
  inputSchema: z.object({
277
280
  id: z.union([z.string(), z.number()]).describe("ID of the remote system Configuration to delete.")
@@ -296,6 +299,7 @@ class CollaboratorClient {
296
299
  register(
297
300
  {
298
301
  title: "Update Remote System Configuration Webhook",
302
+ toolset: "Remote System Configuration Management",
299
303
  summary: "Updates the webhook for a remote system configuration in Collaborator by its ID.",
300
304
  inputSchema: z.object({
301
305
  id: z.union([z.string(), z.number()]).describe(
@@ -322,6 +326,7 @@ class CollaboratorClient {
322
326
  register(
323
327
  {
324
328
  title: "Test Remote System Configuration Connection",
329
+ toolset: "Remote System Configuration Management",
325
330
  summary: "Tests the connection for a remote system configuration in Collaborator by its ID.",
326
331
  inputSchema: z.object({
327
332
  id: z.union([z.string(), z.number()]).describe(