@smartbear/mcp 0.24.0 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/dist/bearq/tool/tasks/chat-with-qa-lead.js +1 -0
  2. package/dist/bearq/tool/tasks/expand-application-model.js +1 -0
  3. package/dist/bearq/tool/tasks/get-task-status.js +1 -0
  4. package/dist/bearq/tool/tasks/get-task.js +1 -0
  5. package/dist/bearq/tool/tasks/refine-all-draft-tests.js +1 -0
  6. package/dist/bearq/tool/tasks/refine-test-cases.js +1 -0
  7. package/dist/bearq/tool/tasks/refine-tests-in-functional-areas.js +1 -0
  8. package/dist/bearq/tool/tasks/run-regression-tests.js +1 -0
  9. package/dist/bearq/tool/tasks/run-test-cases.js +1 -0
  10. package/dist/bearq/tool/tasks/run-tests-in-functional-areas.js +1 -0
  11. package/dist/bearq/tool/tasks/stop-task.js +1 -0
  12. package/dist/bearq/tool/tasks/wait-for-task.js +1 -0
  13. package/dist/bugsnag/client.js +1 -0
  14. package/dist/bugsnag/tool/error/get-error.js +1 -0
  15. package/dist/bugsnag/tool/error/list-project-errors.js +1 -0
  16. package/dist/bugsnag/tool/error/update-error.js +1 -0
  17. package/dist/bugsnag/tool/event/get-event-details-from-dashboard-url.js +1 -0
  18. package/dist/bugsnag/tool/event/get-event.js +1 -0
  19. package/dist/bugsnag/tool/event/list-error-events.js +1 -0
  20. package/dist/bugsnag/tool/performance/get-network-endpoint-groupings.js +1 -0
  21. package/dist/bugsnag/tool/performance/get-span-group.js +1 -0
  22. package/dist/bugsnag/tool/performance/get-trace.js +1 -0
  23. package/dist/bugsnag/tool/performance/list-span-groups.js +1 -0
  24. package/dist/bugsnag/tool/performance/list-spans.js +1 -0
  25. package/dist/bugsnag/tool/performance/list-trace-fields.js +1 -0
  26. package/dist/bugsnag/tool/performance/set-network-endpoint-groupings.js +1 -0
  27. package/dist/bugsnag/tool/project/get-current-project.js +1 -0
  28. package/dist/bugsnag/tool/project/list-project-event-filters.js +1 -0
  29. package/dist/bugsnag/tool/project/list-projects.js +1 -0
  30. package/dist/bugsnag/tool/release/get-build.js +1 -0
  31. package/dist/bugsnag/tool/release/get-release.js +1 -0
  32. package/dist/bugsnag/tool/release/list-releases.js +1 -0
  33. package/dist/collaborator/client.js +10 -0
  34. package/dist/common/client-registry.js +17 -9
  35. package/dist/common/server.js +44 -1
  36. package/dist/common/transport-http.js +24 -20
  37. package/dist/common/transport-stdio.js +7 -5
  38. package/dist/package.json.js +1 -1
  39. package/dist/pactflow/client/tools.js +102 -0
  40. package/dist/qmetry/client/tools/automation-tools.js +2 -0
  41. package/dist/qmetry/client/tools/issue-tools.js +6 -0
  42. package/dist/qmetry/client/tools/project-tools.js +9 -0
  43. package/dist/qmetry/client/tools/requirement-tools.js +5 -0
  44. package/dist/qmetry/client/tools/testcase-tools.js +7 -0
  45. package/dist/qmetry/client/tools/testsuite-tools.js +11 -0
  46. package/dist/qtm4j/client.js +25 -1
  47. package/dist/qtm4j/config/constants.js +101 -1
  48. package/dist/qtm4j/config/field-resolution.types.js +3 -1
  49. package/dist/qtm4j/http/api-client.js +20 -2
  50. package/dist/qtm4j/resolver/resolver-registry.js +7 -1
  51. package/dist/qtm4j/resolver/resolvers/requirement-id-resolver.js +28 -0
  52. package/dist/qtm4j/resolver/resolvers/test-cycle-uid-resolver.js +28 -0
  53. package/dist/qtm4j/schema/linked-items.schema.js +95 -0
  54. package/dist/qtm4j/schema/requirements.schema.js +109 -0
  55. package/dist/qtm4j/schema/test-cycle.link.schema.js +260 -0
  56. package/dist/qtm4j/tool/project/get-projects.js +2 -1
  57. package/dist/qtm4j/tool/project/set-project-context.js +2 -1
  58. package/dist/qtm4j/tool/requirement/get-linked-testcases.js +93 -0
  59. package/dist/qtm4j/tool/requirement/link-testcases.js +107 -0
  60. package/dist/qtm4j/tool/requirement/unlink-testcases.js +97 -0
  61. package/dist/qtm4j/tool/test-automation/get-automation-history.js +2 -1
  62. package/dist/qtm4j/tool/test-automation/upload-automation-result.js +2 -1
  63. package/dist/qtm4j/tool/test-case/create-test-case.js +2 -1
  64. package/dist/qtm4j/tool/test-case/get-linked-requirements.js +67 -0
  65. package/dist/qtm4j/tool/test-case/get-test-cases.js +2 -1
  66. package/dist/qtm4j/tool/test-case/get-test-steps.js +2 -1
  67. package/dist/qtm4j/tool/test-case/link-requirements.js +124 -0
  68. package/dist/qtm4j/tool/test-case/unlink-requirements.js +116 -0
  69. package/dist/qtm4j/tool/test-case/update-test-case.js +2 -1
  70. package/dist/qtm4j/tool/test-cycle/create-test-cycle.js +2 -1
  71. package/dist/qtm4j/tool/test-cycle/get-linked-requirements.js +71 -0
  72. package/dist/qtm4j/tool/test-cycle/link-requirements.js +91 -0
  73. package/dist/qtm4j/tool/test-cycle/link-testcases.js +118 -0
  74. package/dist/qtm4j/tool/test-cycle/search-linked-testcases.js +114 -0
  75. package/dist/qtm4j/tool/test-cycle/search-test-cycle.js +2 -1
  76. package/dist/qtm4j/tool/test-cycle/unlink-requirements.js +87 -0
  77. package/dist/qtm4j/tool/test-cycle/unlink-testcases.js +103 -0
  78. package/dist/qtm4j/tool/test-cycle/update-test-cycle.js +2 -1
  79. package/dist/reflect/tool/recording/add-prompt-step.js +1 -0
  80. package/dist/reflect/tool/recording/add-segment.js +1 -0
  81. package/dist/reflect/tool/recording/connect-to-session.js +1 -0
  82. package/dist/reflect/tool/recording/delete-previous-step.js +1 -0
  83. package/dist/reflect/tool/recording/get-screenshot.js +1 -0
  84. package/dist/reflect/tool/suites/cancel-suite-execution.js +1 -0
  85. package/dist/reflect/tool/suites/execute-suite.js +1 -0
  86. package/dist/reflect/tool/suites/get-suite-execution-status.js +1 -0
  87. package/dist/reflect/tool/suites/list-suite-executions.js +1 -0
  88. package/dist/reflect/tool/suites/list-suites.js +1 -0
  89. package/dist/reflect/tool/tests/get-test-status.js +1 -0
  90. package/dist/reflect/tool/tests/list-segments.js +1 -0
  91. package/dist/reflect/tool/tests/list-tests.js +1 -0
  92. package/dist/reflect/tool/tests/run-test.js +1 -0
  93. package/dist/swagger/client/tools.js +23 -0
  94. package/dist/zephyr/tool/environment/get-environments.js +1 -0
  95. package/dist/zephyr/tool/folder/create-folder.js +1 -0
  96. package/dist/zephyr/tool/issue-link/get-test-cases.js +1 -0
  97. package/dist/zephyr/tool/issue-link/get-test-cycles.js +1 -0
  98. package/dist/zephyr/tool/issue-link/get-test-executions.js +1 -0
  99. package/dist/zephyr/tool/priority/get-priorities.js +1 -0
  100. package/dist/zephyr/tool/project/get-project.js +1 -0
  101. package/dist/zephyr/tool/project/get-projects.js +1 -0
  102. package/dist/zephyr/tool/status/get-statuses.js +1 -0
  103. package/dist/zephyr/tool/test-case/create-issue-link.js +1 -0
  104. package/dist/zephyr/tool/test-case/create-test-case.js +1 -0
  105. package/dist/zephyr/tool/test-case/create-test-script.js +1 -0
  106. package/dist/zephyr/tool/test-case/create-test-steps.js +1 -0
  107. package/dist/zephyr/tool/test-case/create-web-link.js +1 -0
  108. package/dist/zephyr/tool/test-case/get-links.js +1 -0
  109. package/dist/zephyr/tool/test-case/get-test-case.js +1 -0
  110. package/dist/zephyr/tool/test-case/get-test-cases.js +1 -0
  111. package/dist/zephyr/tool/test-case/get-test-script.js +1 -0
  112. package/dist/zephyr/tool/test-case/get-test-steps.js +1 -0
  113. package/dist/zephyr/tool/test-case/update-test-case.js +1 -0
  114. package/dist/zephyr/tool/test-cycle/create-issue-link.js +1 -0
  115. package/dist/zephyr/tool/test-cycle/create-test-cycle.js +1 -0
  116. package/dist/zephyr/tool/test-cycle/create-web-link.js +1 -0
  117. package/dist/zephyr/tool/test-cycle/get-links.js +1 -0
  118. package/dist/zephyr/tool/test-cycle/get-test-cycle.js +1 -0
  119. package/dist/zephyr/tool/test-cycle/get-test-cycles.js +1 -0
  120. package/dist/zephyr/tool/test-cycle/update-test-cycle.js +1 -0
  121. package/dist/zephyr/tool/test-execution/create-issue-link.js +1 -0
  122. package/dist/zephyr/tool/test-execution/create-test-execution.js +1 -0
  123. package/dist/zephyr/tool/test-execution/get-test-execution-links.js +1 -0
  124. package/dist/zephyr/tool/test-execution/get-test-execution.js +1 -0
  125. package/dist/zephyr/tool/test-execution/get-test-executions.js +1 -0
  126. package/dist/zephyr/tool/test-execution/get-test-steps.js +1 -0
  127. package/dist/zephyr/tool/test-execution/update-test-execution.js +1 -0
  128. package/dist/zephyr/tool/test-execution/update-test-steps.js +1 -0
  129. package/package.json +1 -1
@@ -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
  };
@@ -73,6 +73,7 @@ class BugsnagClient {
73
73
  capabilityPrefix = "bugsnag";
74
74
  configPrefix = "Bugsnag";
75
75
  config = ConfigurationSchema;
76
+ defaultToolsets = ["Projects"];
76
77
  async configure(server, config) {
77
78
  this.cache = server.getCache();
78
79
  this._appEndpoint = this.getEndpoint(
@@ -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: [
@@ -64,6 +64,7 @@ class CollaboratorClient {
64
64
  register(
65
65
  {
66
66
  title: "Find Review By ID",
67
+ toolset: "Review Management",
67
68
  summary: "Finds a review in Collaborator by its review ID.",
68
69
  inputSchema: z.object({
69
70
  reviewId: z.string().describe("The Collaborator review ID to find.")
@@ -86,6 +87,7 @@ class CollaboratorClient {
86
87
  register(
87
88
  {
88
89
  title: "Create Review",
90
+ toolset: "Review Management",
89
91
  summary: "Creates a new review in Collaborator. All parameters are optional.",
90
92
  inputSchema: z.object({
91
93
  creator: z.string().optional().describe(
@@ -123,6 +125,7 @@ class CollaboratorClient {
123
125
  register(
124
126
  {
125
127
  title: "Reject Review",
128
+ toolset: "Review Management",
126
129
  summary: "Rejects a review in Collaborator by its review ID and reason.",
127
130
  inputSchema: z.object({
128
131
  reviewId: z.union([z.string(), z.number()]).describe("The Collaborator review ID to reject."),
@@ -149,6 +152,7 @@ class CollaboratorClient {
149
152
  register(
150
153
  {
151
154
  title: "ReviewService Action",
155
+ toolset: "Review Management",
152
156
  summary: "Invoke any ReviewService method by name and arguments. For finishReviewPhase and waitOnPhase, provide reviewId (required) and until (optional, defaults to 'ANY').",
153
157
  inputSchema: z.object({
154
158
  action: z.enum([
@@ -172,6 +176,7 @@ class CollaboratorClient {
172
176
  register(
173
177
  {
174
178
  title: "Get Reviews",
179
+ toolset: "Review Management",
175
180
  summary: "Retrieves reviews from Collaborator using ReviewService.getReviews. All parameters are optional and only provided ones are sent.",
176
181
  inputSchema: z.object({
177
182
  login: z.string().optional().describe("Collaborator username to filter reviews."),
@@ -208,6 +213,7 @@ class CollaboratorClient {
208
213
  register(
209
214
  {
210
215
  title: "Create Remote System Configuration",
216
+ toolset: "Remote System Configuration Management",
211
217
  summary: "Creates a remote system configuration in Collaborator (e.g., Bitbucket, GitHub, etc).",
212
218
  inputSchema: z.object({
213
219
  token: z.string().describe("Remote system token, e.g., BITBUCKET, GITHUB, etc."),
@@ -239,6 +245,7 @@ class CollaboratorClient {
239
245
  register(
240
246
  {
241
247
  title: "Edit Remote System Configuration",
248
+ toolset: "Remote System Configuration Management",
242
249
  summary: "Edits parameters of an existing remote system configuration in Collaborator. Only title and config are editable after creation.",
243
250
  inputSchema: z.object({
244
251
  id: z.string().describe("ID of the remote system Configuration to edit."),
@@ -272,6 +279,7 @@ class CollaboratorClient {
272
279
  register(
273
280
  {
274
281
  title: "Delete Remote System Configuration",
282
+ toolset: "Remote System Configuration Management",
275
283
  summary: "Deletes a remote system configuration in Collaborator by its ID.",
276
284
  inputSchema: z.object({
277
285
  id: z.union([z.string(), z.number()]).describe("ID of the remote system Configuration to delete.")
@@ -296,6 +304,7 @@ class CollaboratorClient {
296
304
  register(
297
305
  {
298
306
  title: "Update Remote System Configuration Webhook",
307
+ toolset: "Remote System Configuration Management",
299
308
  summary: "Updates the webhook for a remote system configuration in Collaborator by its ID.",
300
309
  inputSchema: z.object({
301
310
  id: z.union([z.string(), z.number()]).describe(
@@ -322,6 +331,7 @@ class CollaboratorClient {
322
331
  register(
323
332
  {
324
333
  title: "Test Remote System Configuration Connection",
334
+ toolset: "Remote System Configuration Management",
325
335
  summary: "Tests the connection for a remote system configuration in Collaborator by its ID.",
326
336
  inputSchema: z.object({
327
337
  id: z.union([z.string(), z.number()]).describe(
@@ -2,27 +2,35 @@ import { ZodURL } from "zod";
2
2
  import { fullyUnwrapZodType, isOptionalType } from "./zod-utils.js";
3
3
  class ClientRegistry {
4
4
  entries = [];
5
- enabledClients = null;
5
+ enabledClients;
6
6
  /**
7
- * Configure which clients should be enabled based on MCP_CLIENTS env var
7
+ * Configure which clients should be enabled based on MCP_CLIENTS env var and MCP_TOOLSETS (to enable any referenced clients)
8
8
  * If not set or empty, all clients are enabled
9
9
  * If set, should be comma-separated list of client names (case-insensitive)
10
10
  */
11
11
  constructor() {
12
- const enabledClientsEnv = process.env.MCP_CLIENTS?.trim();
13
- if (!enabledClientsEnv) {
14
- this.enabledClients = null;
15
- return;
12
+ let enabledClientsStr = "";
13
+ if (process.env.MCP_CLIENTS) {
14
+ enabledClientsStr = process.env.MCP_CLIENTS.trim();
15
+ }
16
+ enabledClientsStr += ",";
17
+ if (process.env.MCP_TOOLSETS) {
18
+ enabledClientsStr += process.env.MCP_TOOLSETS.trim();
16
19
  }
17
20
  this.enabledClients = new Set(
18
- enabledClientsEnv.split(",").map((name) => name.trim().toLowerCase()).filter((name) => name.length > 0)
21
+ enabledClientsStr.trim().split(",").map((name) => {
22
+ if (name.includes(":")) {
23
+ return name.split(":")[0].trim().toLowerCase();
24
+ }
25
+ return name.trim().toLowerCase();
26
+ }).filter((name) => name.length > 0)
19
27
  );
20
28
  }
21
29
  /**
22
- * Check if a client is enabled based on MCP_CLIENTS configuration
30
+ * Check if a client is enabled based on client filtering configuration
23
31
  */
24
32
  isClientEnabled(name) {
25
- if (this.enabledClients === null) {
33
+ if (this.enabledClients.size === 0) {
26
34
  return true;
27
35
  }
28
36
  return this.enabledClients.has(name.toLowerCase());
@@ -11,7 +11,8 @@ class SmartBearMcpServer extends McpServer {
11
11
  samplingSupported = false;
12
12
  elicitationSupported = false;
13
13
  clients = [];
14
- constructor() {
14
+ enabledToolsets;
15
+ constructor(enabledToolsets) {
15
16
  super(
16
17
  {
17
18
  name: MCP_SERVER_NAME,
@@ -28,6 +29,9 @@ class SmartBearMcpServer extends McpServer {
28
29
  }
29
30
  );
30
31
  this.cache = new CacheService();
32
+ if (enabledToolsets) {
33
+ this.enabledToolsets = enabledToolsets.split(",").map((s) => s.trim().toLowerCase());
34
+ }
31
35
  }
32
36
  getCache() {
33
37
  return this.cache;
@@ -56,6 +60,9 @@ class SmartBearMcpServer extends McpServer {
56
60
  this.clients.push(client);
57
61
  await client.registerTools(
58
62
  (params, cb) => {
63
+ if (!this.isToolEnabled(client, params.toolset)) {
64
+ return null;
65
+ }
59
66
  const toolName = this.getCapabilityName(client, params.title);
60
67
  const toolTitle = this.getCapabilityTitle(client, params.title);
61
68
  if (toolName.length > 64) {
@@ -236,9 +243,40 @@ ${result.instructions}`
236
243
  getCapabilityName(client, title) {
237
244
  return `${client.capabilityPrefix}_${title.replace(/\s+/g, "_").toLowerCase()}`;
238
245
  }
246
+ /**
247
+ * The tool is enabled if:
248
+ * - No enabled toolsets are defined on the server, or
249
+ * - The client is included in the enabled toolsets list, or
250
+ * - The toolset is included in the enabled toolsets list, or
251
+ * - The toolset is in the client's default list and there is at least one specific toolset enabled for the client
252
+ * @param client
253
+ * @param toolset
254
+ * @returns whether to register the tool based on enabled toolsets configuration
255
+ */
256
+ isToolEnabled(client, toolset) {
257
+ if (!this.enabledToolsets) {
258
+ return true;
259
+ }
260
+ const clientPrefix = client.configPrefix.toLowerCase();
261
+ const clientIsEnabled = this.enabledToolsets.some(
262
+ (ts) => !ts.includes(":") && ts === clientPrefix
263
+ );
264
+ if (clientIsEnabled) {
265
+ return true;
266
+ }
267
+ const toolsetEntries = this.enabledToolsets.filter(
268
+ (ts) => ts.includes(":") && ts.split(":")[0] === clientPrefix
269
+ );
270
+ if (toolsetEntries.length === 0) {
271
+ return false;
272
+ }
273
+ const toolsetName = `${clientPrefix}:${toolset.replace(/[\s\-_]/g, "")}`.toLowerCase();
274
+ return toolsetEntries.includes(toolsetName) || (client.defaultToolsets || [])?.includes(toolset);
275
+ }
239
276
  getDescription(params) {
240
277
  const {
241
278
  summary,
279
+ toolset,
242
280
  useCases,
243
281
  examples,
244
282
  inputSchema,
@@ -246,6 +284,11 @@ ${result.instructions}`
246
284
  outputDescription
247
285
  } = params;
248
286
  let description = summary;
287
+ if (toolset) {
288
+ description += `
289
+
290
+ **Toolset:** ${toolset}`;
291
+ }
249
292
  if (inputSchema && inputSchema instanceof ZodObject) {
250
293
  let parameters = Object.keys(inputSchema.shape).map((key) => {
251
294
  const field = inputSchema.shape[key];
@@ -343,27 +343,31 @@ async function handleLegacyMessageRequest(req, res, url, transports) {
343
343
  }
344
344
  });
345
345
  }
346
+ function getConfigValue(clientPrefix, key, req) {
347
+ const queryStringName = getQueryStringName(clientPrefix, key);
348
+ const queryParams = querystring.parse(req.url?.split("?")[1] || "");
349
+ let value = queryParams[queryStringName] || queryParams[queryStringName.toLowerCase()];
350
+ if (typeof value === "string") {
351
+ return value;
352
+ }
353
+ const headerName = getHeaderName(clientPrefix, key);
354
+ value = req.headers[headerName] || req.headers[headerName.toLowerCase()];
355
+ if (typeof value === "string") {
356
+ return value;
357
+ }
358
+ const envVarName = getEnvVarName(clientPrefix, key);
359
+ return process.env[envVarName] || null;
360
+ }
346
361
  async function newServer(req, res) {
347
- const server = new SmartBearMcpServer();
362
+ const enabledToolsets = getConfigValue("smartbear", "toolsets", req) || void 0;
363
+ const server = new SmartBearMcpServer(enabledToolsets);
348
364
  try {
349
365
  const configuredCount = await withRequestContext(
350
366
  req,
351
367
  () => clientRegistry.configure(
352
368
  server,
353
369
  (client, key) => {
354
- const queryStringName = getQueryStringName(client, key);
355
- const queryParams = querystring.parse(req.url?.split("?")[1] || "");
356
- let value = queryParams[queryStringName] || queryParams[queryStringName.toLowerCase()];
357
- if (typeof value === "string") {
358
- return value;
359
- }
360
- const headerName = getHeaderName(client, key);
361
- value = req.headers[headerName] || req.headers[headerName.toLowerCase()];
362
- if (typeof value === "string") {
363
- return value;
364
- }
365
- const envVarName = getEnvVarName(client, key);
366
- return process.env[envVarName] || null;
370
+ return getConfigValue(client.configPrefix, key, req);
367
371
  },
368
372
  true
369
373
  // ignoreMissingRequiredConfigs
@@ -405,13 +409,13 @@ ${headerHelp.join("\n")}` : "No clients support HTTP header configuration.";
405
409
  }
406
410
  return server;
407
411
  }
408
- function getHeaderName(client, key) {
409
- return `${client.configPrefix}-${key.split("_").map(
412
+ function getHeaderName(clientPrefix, key) {
413
+ return `${clientPrefix}-${key.split("_").map(
410
414
  (part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()
411
415
  ).join("-")}`;
412
416
  }
413
- function getQueryStringName(client, key) {
414
- return `${client.configPrefix.toLowerCase()}${key.split("_").map(
417
+ function getQueryStringName(clientPrefix, key) {
418
+ return `${clientPrefix.toLowerCase()}${key.split("_").map(
415
419
  (part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()
416
420
  ).join("")}`;
417
421
  }
@@ -419,7 +423,7 @@ function getHttpHeaders() {
419
423
  const headers = /* @__PURE__ */ new Set();
420
424
  for (const entry of clientRegistry.getAll()) {
421
425
  for (const configKey of Object.keys(entry.config.shape)) {
422
- headers.add(getHeaderName(entry, configKey));
426
+ headers.add(getHeaderName(entry.configPrefix, configKey));
423
427
  }
424
428
  }
425
429
  return Array.from(headers).sort((a, b) => a.localeCompare(b));
@@ -429,7 +433,7 @@ function getHttpHeadersHelp() {
429
433
  for (const entry of clientRegistry.getAll()) {
430
434
  messages.push(` - ${entry.name}:`);
431
435
  for (const [configKey, requirement] of Object.entries(entry.config.shape)) {
432
- const headerName = getHeaderName(entry, configKey);
436
+ const headerName = getHeaderName(entry.configPrefix, configKey);
433
437
  const requiredTag = isOptionalType(requirement) ? " (optional)" : " (required)";
434
438
  messages.push(
435
439
  ` - ${headerName}${requiredTag}: ${getTypeDescription(requirement)}`
@@ -1,3 +1,4 @@
1
+ import { enableCompileCache } from "node:module";
1
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
3
  import { clientRegistry } from "./client-registry.js";
3
4
  import { MCP_SERVER_NAME, MCP_SERVER_VERSION } from "./info.js";
@@ -9,7 +10,7 @@ function getNoConfigMessage() {
9
10
  for (const entry of clientRegistry.getAll()) {
10
11
  messages.push(` - ${entry.name}:`);
11
12
  for (const [configKey, requirement] of Object.entries(entry.config.shape)) {
12
- const envVarName = getEnvVarName(entry, configKey);
13
+ const envVarName = getEnvVarName(entry.configPrefix, configKey);
13
14
  const requiredTag = isOptionalType(requirement) ? " (optional)" : " (required)";
14
15
  messages.push(
15
16
  ` - ${envVarName}${requiredTag}: ${getTypeDescription(requirement)}`
@@ -29,11 +30,12 @@ async function runStdioMode() {
29
30
  console.log(getNoConfigMessage().join("\n"));
30
31
  process.exit(0);
31
32
  }
32
- const server = new SmartBearMcpServer();
33
+ enableCompileCache();
34
+ const server = new SmartBearMcpServer(process.env.MCP_TOOLSETS);
33
35
  const configuredCount = await clientRegistry.configure(
34
36
  server,
35
37
  (client, key) => {
36
- const envVarName = getEnvVarName(client, key);
38
+ const envVarName = getEnvVarName(client.configPrefix, key);
37
39
  return process.env[envVarName] || null;
38
40
  }
39
41
  );
@@ -70,8 +72,8 @@ ${message.join("\n")}` : "No clients support environment variable configuration.
70
72
  };
71
73
  await server.connect(transport);
72
74
  }
73
- function getEnvVarName(client, key) {
74
- return `${client.configPrefix.toUpperCase().replace(/-/g, "_")}_${key.toUpperCase()}`;
75
+ function getEnvVarName(clientPrefix, key) {
76
+ return `${clientPrefix.toUpperCase().replace(/-/g, "_")}_${key.toUpperCase()}`;
75
77
  }
76
78
  export {
77
79
  getEnvVarName,
@@ -1,4 +1,4 @@
1
- const version = "0.24.0";
1
+ const version = "0.25.1";
2
2
  const config = { "mcpServerName": "SmartBear MCP Server" };
3
3
  const packageJson = {
4
4
  version,