@smartbear/mcp 0.15.0 → 0.16.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 (47) hide show
  1. package/dist/bugsnag/client.js +42 -1310
  2. package/dist/bugsnag/input-schemas.js +18 -18
  3. package/dist/bugsnag/tool/error/get-error.js +98 -0
  4. package/dist/bugsnag/tool/error/list-project-errors.js +102 -0
  5. package/dist/bugsnag/tool/error/update-error.js +256 -0
  6. package/dist/bugsnag/tool/event/get-event-details-from-dashboard-url.js +55 -0
  7. package/dist/bugsnag/tool/event/get-event.js +38 -0
  8. package/dist/bugsnag/tool/performance/get-network-endpoint-groupings.js +46 -0
  9. package/dist/bugsnag/tool/performance/get-span-group.js +73 -0
  10. package/dist/bugsnag/tool/performance/get-trace.js +83 -0
  11. package/dist/bugsnag/tool/performance/list-span-groups.js +111 -0
  12. package/dist/bugsnag/tool/performance/list-spans.js +97 -0
  13. package/dist/bugsnag/tool/performance/list-trace-fields.js +41 -0
  14. package/dist/bugsnag/tool/performance/set-network-endpoint-groupings.js +90 -0
  15. package/dist/bugsnag/tool/project/get-current-project.js +31 -0
  16. package/dist/bugsnag/tool/project/list-project-event-filters.js +42 -0
  17. package/dist/bugsnag/tool/project/list-projects.js +43 -0
  18. package/dist/bugsnag/tool/release/get-build.js +50 -0
  19. package/dist/bugsnag/tool/release/get-release.js +68 -0
  20. package/dist/bugsnag/tool/release/list-releases.js +88 -0
  21. package/dist/common/prompts.js +9 -0
  22. package/dist/common/server.js +16 -0
  23. package/dist/common/transport-http.js +2 -0
  24. package/dist/package.json.js +1 -1
  25. package/dist/reflect/client.js +66 -1
  26. package/dist/reflect/config/constants.js +3 -1
  27. package/dist/reflect/prompt/sap-test.js +29 -0
  28. package/dist/reflect/tool/recording/add-prompt-step.js +60 -0
  29. package/dist/reflect/tool/recording/add-segment.js +56 -0
  30. package/dist/reflect/tool/recording/connect-to-session.js +89 -0
  31. package/dist/reflect/tool/recording/delete-previous-step.js +47 -0
  32. package/dist/reflect/tool/recording/get-screenshot.js +55 -0
  33. package/dist/reflect/tool/tests/list-segments.js +68 -0
  34. package/dist/reflect/websocket-manager.js +92 -0
  35. package/dist/zephyr/common/rest-api-schemas.js +213 -272
  36. package/dist/zephyr/tool/issue-link/get-test-executions.js +1 -1
  37. package/dist/zephyr/tool/test-case/create-issue-link.js +4 -2
  38. package/dist/zephyr/tool/test-case/create-test-script.js +4 -2
  39. package/dist/zephyr/tool/test-case/create-test-steps.js +4 -2
  40. package/dist/zephyr/tool/test-case/create-web-link.js +5 -2
  41. package/dist/zephyr/tool/test-case/get-test-steps.js +4 -2
  42. package/dist/zephyr/tool/test-cycle/create-issue-link.js +4 -2
  43. package/dist/zephyr/tool/test-cycle/create-web-link.js +4 -2
  44. package/dist/zephyr/tool/test-execution/create-issue-link.js +4 -2
  45. package/dist/zephyr/tool/test-execution/get-test-steps.js +4 -2
  46. package/dist/zephyr/tool/test-execution/update-test-execution.js +5 -2
  47. package/package.json +11 -9
@@ -0,0 +1,55 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { Tool, ToolError } from "../../../common/tools.js";
4
+ class GetScreenshot extends Tool {
5
+ specification = {
6
+ title: "Get Screenshot",
7
+ summary: "Capture a screenshot from the current state of an active Reflect recording session",
8
+ readOnly: true,
9
+ idempotent: true,
10
+ parameters: [
11
+ {
12
+ name: "sessionId",
13
+ type: z.string(),
14
+ description: "The ID of the Reflect recording session",
15
+ required: true
16
+ }
17
+ ]
18
+ };
19
+ handle = async (args) => {
20
+ const { sessionId } = args;
21
+ if (!sessionId) throw new ToolError("sessionId argument is required");
22
+ const wsManager = this.client.getConnectedSession(sessionId);
23
+ const id = randomUUID();
24
+ const responsePromise = wsManager.waitForResponse(id);
25
+ await wsManager.sendMcpMessage({
26
+ type: "mcp:get-screenshot",
27
+ id
28
+ });
29
+ const response = await responsePromise;
30
+ const { imageBase64, state } = response;
31
+ if (!imageBase64) {
32
+ throw new ToolError("No imageBase64 in screenshot response");
33
+ }
34
+ return {
35
+ content: [
36
+ {
37
+ type: "image",
38
+ data: imageBase64,
39
+ mimeType: "image/png"
40
+ },
41
+ {
42
+ type: "text",
43
+ text: JSON.stringify({
44
+ success: true,
45
+ message: "Screenshot captured",
46
+ state
47
+ })
48
+ }
49
+ ]
50
+ };
51
+ };
52
+ }
53
+ export {
54
+ GetScreenshot
55
+ };
@@ -0,0 +1,68 @@
1
+ import { z } from "zod";
2
+ import { Tool, ToolError } from "../../../common/tools.js";
3
+ import { API_HOSTNAME, API_KEY_HEADER } from "../../config/constants.js";
4
+ class ListSegments extends Tool {
5
+ specification = {
6
+ title: "List Segments",
7
+ summary: "Retrieve available reusable test segments for the given platform type. Segments are reusable test steps with an optional set of parameters that can used across multiple tests.",
8
+ readOnly: true,
9
+ idempotent: true,
10
+ parameters: [
11
+ {
12
+ name: "platform",
13
+ type: z.enum(["api", "native-mobile", "web"]),
14
+ description: "The platform type to retrieve segments for",
15
+ required: true
16
+ },
17
+ {
18
+ name: "offset",
19
+ type: z.number(),
20
+ description: "Offset for pagination",
21
+ required: false
22
+ },
23
+ {
24
+ name: "limit",
25
+ type: z.number(),
26
+ description: "Maximum number of segments to return",
27
+ required: false
28
+ }
29
+ ]
30
+ };
31
+ handle = async (args) => {
32
+ const {
33
+ platform,
34
+ offset = 0,
35
+ limit = 25
36
+ } = args;
37
+ const url = `https://${API_HOSTNAME}/v1/segments?type=${platform}&offset=${offset}&limit=${limit}`;
38
+ const response = await fetch(url, {
39
+ method: "GET",
40
+ headers: {
41
+ [API_KEY_HEADER]: this.client.getApiToken(),
42
+ "Content-Type": "application/json"
43
+ }
44
+ });
45
+ if (!response.ok) {
46
+ throw new ToolError(
47
+ `Failed to list segments: ${response.status} ${response.statusText}`
48
+ );
49
+ }
50
+ const data = await response.json();
51
+ return {
52
+ content: [
53
+ {
54
+ type: "text",
55
+ text: JSON.stringify({
56
+ success: true,
57
+ segments: data.segments,
58
+ count: data.count,
59
+ message: `Found ${data.count} segment(s) for platform '${platform}'`
60
+ })
61
+ }
62
+ ]
63
+ };
64
+ };
65
+ }
66
+ export {
67
+ ListSegments
68
+ };
@@ -0,0 +1,92 @@
1
+ import WebSocket from "ws";
2
+ import { WEBSOCKET_HOSTNAME, API_KEY_HEADER } from "./config/constants.js";
3
+ class WebSocketManager {
4
+ sessionId;
5
+ apiKey;
6
+ mcpSocket = null;
7
+ pendingResponses = /* @__PURE__ */ new Map();
8
+ constructor(sessionId, apiKey) {
9
+ this.sessionId = sessionId;
10
+ this.apiKey = apiKey;
11
+ }
12
+ async connect() {
13
+ if (this.mcpSocket?.readyState === WebSocket.OPEN) {
14
+ throw new Error("WebSocket is already connected");
15
+ }
16
+ try {
17
+ await this.connectMcpSocket();
18
+ } catch (error) {
19
+ throw new Error(
20
+ `Failed to connect WebSocket: ${error.message}`
21
+ );
22
+ }
23
+ }
24
+ async connectMcpSocket() {
25
+ return new Promise((resolve, reject) => {
26
+ const url = `wss://${WEBSOCKET_HOSTNAME}/websocket/v2/recordings/${this.sessionId}/topics/mcp?sid=${this.sessionId}`;
27
+ this.mcpSocket = new WebSocket(url, {
28
+ headers: {
29
+ [API_KEY_HEADER]: this.apiKey
30
+ }
31
+ });
32
+ this.mcpSocket.on("open", () => {
33
+ resolve();
34
+ });
35
+ this.mcpSocket.on("message", (data) => {
36
+ try {
37
+ const message = JSON.parse(data.toString());
38
+ const { id, type } = message;
39
+ if (id && this.pendingResponses.has(id)) {
40
+ const pending = this.pendingResponses.get(id);
41
+ this.pendingResponses.delete(id);
42
+ if (type?.endsWith(":success")) {
43
+ pending.resolve(message);
44
+ } else if (type?.endsWith(":failure")) {
45
+ pending.reject(message);
46
+ }
47
+ }
48
+ } catch (error) {
49
+ console.error("Failed to parse MCP message:", error);
50
+ }
51
+ });
52
+ this.mcpSocket.on("error", (error) => {
53
+ reject(new Error(`MCP socket error: ${error.message}`));
54
+ });
55
+ });
56
+ }
57
+ async sendMcpMessage(message) {
58
+ if (!this.mcpSocket || this.mcpSocket.readyState !== WebSocket.OPEN) {
59
+ throw new Error("WebSocket is not connected");
60
+ }
61
+ return new Promise((resolve, reject) => {
62
+ this.mcpSocket?.send(JSON.stringify(message), (error) => {
63
+ if (error) {
64
+ reject(new Error(`Failed to send MCP message: ${error.message}`));
65
+ } else {
66
+ resolve();
67
+ }
68
+ });
69
+ });
70
+ }
71
+ waitForResponse(id) {
72
+ return new Promise((resolve, reject) => {
73
+ this.pendingResponses.set(id, { resolve, reject });
74
+ });
75
+ }
76
+ async disconnect() {
77
+ if (this.mcpSocket) {
78
+ this.mcpSocket.removeAllListeners();
79
+ if (this.mcpSocket.readyState === WebSocket.OPEN || this.mcpSocket.readyState === WebSocket.CONNECTING) {
80
+ this.mcpSocket.close();
81
+ }
82
+ this.mcpSocket = null;
83
+ }
84
+ await new Promise((resolve) => setTimeout(resolve, 100));
85
+ }
86
+ isConnected() {
87
+ return this.mcpSocket?.readyState === WebSocket.OPEN;
88
+ }
89
+ }
90
+ export {
91
+ WebSocketManager
92
+ };