@browserstack/mcp-server 1.0.12 → 1.0.14

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 (52) hide show
  1. package/README.md +22 -0
  2. package/dist/config.js +2 -6
  3. package/dist/index.js +31 -30
  4. package/dist/lib/api.js +3 -57
  5. package/dist/lib/constants.js +14 -0
  6. package/dist/lib/device-cache.js +32 -33
  7. package/dist/lib/error.js +3 -6
  8. package/dist/lib/fuzzy.js +1 -4
  9. package/dist/lib/inmemory-store.js +1 -0
  10. package/dist/lib/instrumentation.js +12 -18
  11. package/dist/lib/local.js +27 -35
  12. package/dist/lib/utils.js +29 -4
  13. package/dist/logger.js +4 -9
  14. package/dist/tools/accessibility.js +9 -12
  15. package/dist/tools/accessiblity-utils/accessibility.js +14 -22
  16. package/dist/tools/appautomate-utils/appautomate.js +95 -0
  17. package/dist/tools/appautomate.js +116 -0
  18. package/dist/tools/applive-utils/fuzzy-search.js +3 -6
  19. package/dist/tools/applive-utils/start-session.js +14 -20
  20. package/dist/tools/applive-utils/upload-app.js +12 -51
  21. package/dist/tools/applive.js +18 -25
  22. package/dist/tools/automate-utils/fetch-screenshots.js +59 -0
  23. package/dist/tools/automate.js +44 -37
  24. package/dist/tools/bstack-sdk.js +14 -18
  25. package/dist/tools/failurelogs-utils/app-automate.js +88 -0
  26. package/dist/tools/failurelogs-utils/automate.js +97 -0
  27. package/dist/tools/getFailureLogs.js +173 -0
  28. package/dist/tools/live-utils/desktop-filter.js +8 -11
  29. package/dist/tools/live-utils/mobile-filter.js +7 -10
  30. package/dist/tools/live-utils/start-session.js +17 -23
  31. package/dist/tools/live-utils/types.js +2 -5
  32. package/dist/tools/live-utils/version-resolver.js +1 -4
  33. package/dist/tools/live.js +23 -29
  34. package/dist/tools/observability.js +12 -19
  35. package/dist/tools/sdk-utils/constants.js +3 -9
  36. package/dist/tools/sdk-utils/instructions.js +4 -9
  37. package/dist/tools/sdk-utils/types.js +1 -2
  38. package/dist/tools/testmanagement-utils/TCG-utils/api.js +259 -0
  39. package/dist/tools/testmanagement-utils/TCG-utils/config.js +5 -0
  40. package/dist/tools/testmanagement-utils/TCG-utils/helpers.js +53 -0
  41. package/dist/tools/testmanagement-utils/TCG-utils/types.js +8 -0
  42. package/dist/tools/testmanagement-utils/add-test-result.js +61 -0
  43. package/dist/tools/testmanagement-utils/create-project-folder.js +21 -28
  44. package/dist/tools/testmanagement-utils/create-testcase.js +30 -38
  45. package/dist/tools/testmanagement-utils/create-testrun.js +23 -30
  46. package/dist/tools/testmanagement-utils/list-testcases.js +16 -23
  47. package/dist/tools/testmanagement-utils/list-testruns.js +13 -20
  48. package/dist/tools/testmanagement-utils/testcase-from-file.js +42 -0
  49. package/dist/tools/testmanagement-utils/update-testrun.js +16 -23
  50. package/dist/tools/testmanagement-utils/upload-file.js +101 -0
  51. package/dist/tools/testmanagement.js +115 -46
  52. package/package.json +10 -6
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ import axios from "axios";
3
+ import FormData from "form-data";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import { v4 as uuidv4 } from "uuid";
7
+ import config from "../../config.js";
8
+ import { signedUrlMap } from "../../lib/inmemory-store.js";
9
+ import { projectIdentifierToId } from "./TCG-utils/api.js";
10
+ /**
11
+ * Schema for the upload file tool
12
+ */
13
+ export const UploadFileSchema = z.object({
14
+ project_identifier: z
15
+ .string()
16
+ .describe("ID of the project where the file should be uploaded. Do not assume it, always ask user for it."),
17
+ file_path: z
18
+ .string()
19
+ .describe("Full path to the file that should be uploaded"),
20
+ });
21
+ /**
22
+ * Uploads a file to BrowserStack Test Management and returns the signed URL.
23
+ */
24
+ export async function uploadFile(args) {
25
+ const { project_identifier, file_path } = args;
26
+ try {
27
+ // Validate file exists
28
+ if (!fs.existsSync(file_path)) {
29
+ return {
30
+ content: [
31
+ {
32
+ type: "text",
33
+ text: `File ${file_path} does not exist.`,
34
+ isError: true,
35
+ },
36
+ ],
37
+ isError: true,
38
+ };
39
+ }
40
+ // Get the project ID
41
+ const projectIdResponse = await projectIdentifierToId(project_identifier);
42
+ const formData = new FormData();
43
+ formData.append("attachments[]", fs.createReadStream(file_path));
44
+ const uploadUrl = `https://test-management.browserstack.com/api/v1/projects/${projectIdResponse}/generic/attachments/ai_uploads`;
45
+ const response = await axios.post(uploadUrl, formData, {
46
+ headers: {
47
+ ...formData.getHeaders(),
48
+ "API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
49
+ accept: "application/json, text/plain, */*",
50
+ },
51
+ });
52
+ if (response.status >= 200 &&
53
+ response.status < 300 &&
54
+ response.data.generic_attachment) {
55
+ const attachments = response.data.generic_attachment.map((attachment) => {
56
+ // Generate a unique ID for each attachment
57
+ const fileId = uuidv4();
58
+ // Store the download URL in the signedUrlMap
59
+ const data = {
60
+ fileId: attachment.id,
61
+ downloadUrl: attachment.download_url,
62
+ };
63
+ signedUrlMap.set(fileId, data);
64
+ return {
65
+ name: attachment.name,
66
+ documentID: fileId,
67
+ contentType: attachment.content_type,
68
+ size: attachment.size,
69
+ projectReferenceId: projectIdResponse,
70
+ };
71
+ });
72
+ return {
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: `Successfully uploaded ${path.basename(file_path)} to BrowserStack Test Management.`,
77
+ },
78
+ {
79
+ type: "text",
80
+ text: JSON.stringify(attachments, null, 2),
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ else {
86
+ throw new Error(`Unexpected response: ${JSON.stringify(response.data)}`);
87
+ }
88
+ }
89
+ catch (error) {
90
+ return {
91
+ content: [
92
+ {
93
+ type: "text",
94
+ text: `Failed to upload file: ${error instanceof Error ? error.message : "Unknown error"}. Please check your credentials and try again.`,
95
+ isError: true,
96
+ },
97
+ ],
98
+ isError: true,
99
+ };
100
+ }
101
+ }
@@ -1,36 +1,28 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createProjectOrFolderTool = createProjectOrFolderTool;
7
- exports.createTestCaseTool = createTestCaseTool;
8
- exports.listTestCasesTool = listTestCasesTool;
9
- exports.createTestRunTool = createTestRunTool;
10
- exports.listTestRunsTool = listTestRunsTool;
11
- exports.updateTestRunTool = updateTestRunTool;
12
- exports.default = addTestManagementTools;
13
- const instrumentation_1 = require("../lib/instrumentation");
14
- const logger_1 = __importDefault(require("../logger"));
15
- const create_project_folder_1 = require("./testmanagement-utils/create-project-folder");
16
- const create_testcase_1 = require("./testmanagement-utils/create-testcase");
1
+ import { trackMCP } from "../lib/instrumentation.js";
2
+ import logger from "../logger.js";
3
+ import { createProjectOrFolder, CreateProjFoldSchema, } from "./testmanagement-utils/create-project-folder.js";
4
+ import { createTestCase as createTestCaseAPI, sanitizeArgs, CreateTestCaseSchema, } from "./testmanagement-utils/create-testcase.js";
17
5
  let serverInstance;
18
- const list_testcases_1 = require("./testmanagement-utils/list-testcases");
19
- const create_testrun_1 = require("./testmanagement-utils/create-testrun");
20
- const list_testruns_1 = require("./testmanagement-utils/list-testruns");
21
- const update_testrun_1 = require("./testmanagement-utils/update-testrun");
6
+ import { listTestCases, ListTestCasesSchema, } from "./testmanagement-utils/list-testcases.js";
7
+ import { CreateTestRunSchema, createTestRun, } from "./testmanagement-utils/create-testrun.js";
8
+ import { ListTestRunsSchema, listTestRuns, } from "./testmanagement-utils/list-testruns.js";
9
+ import { UpdateTestRunSchema, updateTestRun, } from "./testmanagement-utils/update-testrun.js";
10
+ import { addTestResult, AddTestResultSchema, } from "./testmanagement-utils/add-test-result.js";
11
+ import { UploadFileSchema, uploadFile, } from "./testmanagement-utils/upload-file.js";
12
+ import { createTestCasesFromFile } from "./testmanagement-utils/testcase-from-file.js";
13
+ import { CreateTestCasesFromFileSchema } from "./testmanagement-utils/TCG-utils/types.js";
22
14
  //TODO: Moving the traceMCP and catch block to the parent(server) function
23
15
  /**
24
16
  * Wrapper to call createProjectOrFolder util.
25
17
  */
26
- async function createProjectOrFolderTool(args) {
18
+ export async function createProjectOrFolderTool(args) {
27
19
  try {
28
- (0, instrumentation_1.trackMCP)("createProjectOrFolder", serverInstance.server.getClientVersion());
29
- return await (0, create_project_folder_1.createProjectOrFolder)(args);
20
+ trackMCP("createProjectOrFolder", serverInstance.server.getClientVersion());
21
+ return await createProjectOrFolder(args);
30
22
  }
31
23
  catch (err) {
32
- logger_1.default.error("Failed to create project/folder: %s", err);
33
- (0, instrumentation_1.trackMCP)("createProjectOrFolder", serverInstance.server.getClientVersion(), err);
24
+ logger.error("Failed to create project/folder: %s", err);
25
+ trackMCP("createProjectOrFolder", serverInstance.server.getClientVersion(), err);
34
26
  return {
35
27
  content: [
36
28
  {
@@ -46,16 +38,16 @@ async function createProjectOrFolderTool(args) {
46
38
  /**
47
39
  * Creates a test case in BrowserStack Test Management.
48
40
  */
49
- async function createTestCaseTool(args) {
41
+ export async function createTestCaseTool(args) {
50
42
  // Sanitize input arguments
51
- const cleanedArgs = (0, create_testcase_1.sanitizeArgs)(args);
43
+ const cleanedArgs = sanitizeArgs(args);
52
44
  try {
53
- (0, instrumentation_1.trackMCP)("createTestCase", serverInstance.server.getClientVersion());
54
- return await (0, create_testcase_1.createTestCase)(cleanedArgs);
45
+ trackMCP("createTestCase", serverInstance.server.getClientVersion());
46
+ return await createTestCaseAPI(cleanedArgs);
55
47
  }
56
48
  catch (err) {
57
- logger_1.default.error("Failed to create test case: %s", err);
58
- (0, instrumentation_1.trackMCP)("createTestCase", serverInstance.server.getClientVersion(), err);
49
+ logger.error("Failed to create test case: %s", err);
50
+ trackMCP("createTestCase", serverInstance.server.getClientVersion(), err);
59
51
  return {
60
52
  content: [
61
53
  {
@@ -71,11 +63,13 @@ async function createTestCaseTool(args) {
71
63
  /**
72
64
  * Lists test cases in a project with optional filters (status, priority, custom fields, etc.)
73
65
  */
74
- async function listTestCasesTool(args) {
66
+ export async function listTestCasesTool(args) {
75
67
  try {
76
- return await (0, list_testcases_1.listTestCases)(args);
68
+ trackMCP("listTestCases", serverInstance.server.getClientVersion());
69
+ return await listTestCases(args);
77
70
  }
78
71
  catch (err) {
72
+ trackMCP("listTestCases", serverInstance.server.getClientVersion(), err);
79
73
  return {
80
74
  content: [
81
75
  {
@@ -91,11 +85,13 @@ async function listTestCasesTool(args) {
91
85
  /**
92
86
  * Creates a test run in BrowserStack Test Management.
93
87
  */
94
- async function createTestRunTool(args) {
88
+ export async function createTestRunTool(args) {
95
89
  try {
96
- return await (0, create_testrun_1.createTestRun)(args);
90
+ trackMCP("createTestRun", serverInstance.server.getClientVersion());
91
+ return await createTestRun(args);
97
92
  }
98
93
  catch (err) {
94
+ trackMCP("createTestRun", serverInstance.server.getClientVersion(), err);
99
95
  return {
100
96
  content: [
101
97
  {
@@ -111,11 +107,13 @@ async function createTestRunTool(args) {
111
107
  /**
112
108
  * Lists test runs in a project with optional filters (date ranges, assignee, state, etc.)
113
109
  */
114
- async function listTestRunsTool(args) {
110
+ export async function listTestRunsTool(args) {
115
111
  try {
116
- return await (0, list_testruns_1.listTestRuns)(args);
112
+ trackMCP("listTestRuns", serverInstance.server.getClientVersion());
113
+ return await listTestRuns(args);
117
114
  }
118
115
  catch (err) {
116
+ trackMCP("listTestRuns", serverInstance.server.getClientVersion(), err);
119
117
  return {
120
118
  content: [
121
119
  {
@@ -133,11 +131,13 @@ async function listTestRunsTool(args) {
133
131
  * This function allows for partial updates to an existing test run.
134
132
  * It takes the project identifier and test run ID as parameters.
135
133
  */
136
- async function updateTestRunTool(args) {
134
+ export async function updateTestRunTool(args) {
137
135
  try {
138
- return await (0, update_testrun_1.updateTestRun)(args);
136
+ trackMCP("updateTestRun", serverInstance.server.getClientVersion());
137
+ return await updateTestRun(args);
139
138
  }
140
139
  catch (err) {
140
+ trackMCP("updateTestRun", serverInstance.server.getClientVersion(), err);
141
141
  return {
142
142
  content: [
143
143
  {
@@ -150,15 +150,84 @@ async function updateTestRunTool(args) {
150
150
  };
151
151
  }
152
152
  }
153
+ /**
154
+ * Adds a test result to a specific test run via BrowserStack Test Management API.
155
+ */
156
+ export async function addTestResultTool(args) {
157
+ try {
158
+ trackMCP("addTestResult", serverInstance.server.getClientVersion());
159
+ return await addTestResult(args);
160
+ }
161
+ catch (err) {
162
+ trackMCP("addTestResult", serverInstance.server.getClientVersion(), err);
163
+ return {
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: `Failed to add test result: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
168
+ isError: true,
169
+ },
170
+ ],
171
+ isError: true,
172
+ };
173
+ }
174
+ }
175
+ /**
176
+ * Uploads files such as PDRs or screenshots to BrowserStack Test Management and get file mapping ID back.
177
+ */
178
+ export async function uploadFileTestManagementTool(args) {
179
+ try {
180
+ trackMCP("uploadFileTestManagement", serverInstance.server.getClientVersion());
181
+ return await uploadFile(args);
182
+ }
183
+ catch (err) {
184
+ trackMCP("uploadFileTestManagement", serverInstance.server.getClientVersion(), err);
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: `Failed to upload file: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
190
+ isError: true,
191
+ },
192
+ ],
193
+ isError: true,
194
+ };
195
+ }
196
+ }
197
+ /**
198
+ * Creates test cases from a file in BrowserStack Test Management.
199
+ */
200
+ export async function createTestCasesFromFileTool(args, context) {
201
+ try {
202
+ trackMCP("createTestCasesFromFile", serverInstance.server.getClientVersion());
203
+ return await createTestCasesFromFile(args, context);
204
+ }
205
+ catch (err) {
206
+ trackMCP("createTestCasesFromFile", serverInstance.server.getClientVersion(), err);
207
+ return {
208
+ content: [
209
+ {
210
+ type: "text",
211
+ text: `Failed to create test cases from file: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
212
+ isError: true,
213
+ },
214
+ ],
215
+ isError: true,
216
+ };
217
+ }
218
+ }
153
219
  /**
154
220
  * Registers both project/folder and test-case tools.
155
221
  */
156
- function addTestManagementTools(server) {
222
+ export default function addTestManagementTools(server) {
157
223
  serverInstance = server;
158
- server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management.", create_project_folder_1.CreateProjFoldSchema.shape, createProjectOrFolderTool);
159
- server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management.", create_testcase_1.CreateTestCaseSchema.shape, createTestCaseTool);
160
- server.tool("listTestCases", "List test cases in a project with optional filters (status, priority, custom fields, etc.)", list_testcases_1.ListTestCasesSchema.shape, listTestCasesTool);
161
- server.tool("createTestRun", "Create a test run in BrowserStack Test Management.", create_testrun_1.CreateTestRunSchema.shape, createTestRunTool);
162
- server.tool("listTestRuns", "List test runs in a project with optional filters (date ranges, assignee, state, etc.)", list_testruns_1.ListTestRunsSchema.shape, listTestRunsTool);
163
- server.tool("updateTestRun", "Update a test run in BrowserStack Test Management.", update_testrun_1.UpdateTestRunSchema.shape, updateTestRunTool);
224
+ server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management.", CreateProjFoldSchema.shape, createProjectOrFolderTool);
225
+ server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management.", CreateTestCaseSchema.shape, createTestCaseTool);
226
+ server.tool("listTestCases", "List test cases in a project with optional filters (status, priority, custom fields, etc.)", ListTestCasesSchema.shape, listTestCasesTool);
227
+ server.tool("createTestRun", "Create a test run in BrowserStack Test Management.", CreateTestRunSchema.shape, createTestRunTool);
228
+ server.tool("listTestRuns", "List test runs in a project with optional filters (date ranges, assignee, state, etc.)", ListTestRunsSchema.shape, listTestRunsTool);
229
+ server.tool("updateTestRun", "Update a test run in BrowserStack Test Management.", UpdateTestRunSchema.shape, updateTestRunTool);
230
+ server.tool("addTestResult", "Add a test result to a specific test run via BrowserStack Test Management API.", AddTestResultSchema.shape, addTestResultTool);
231
+ server.tool("uploadFileTestManagement", "Upload files such as PDRs or PDFs to BrowserStack Test Management and get file mapping ID back. Its Used for generating test cases from file.", UploadFileSchema.shape, uploadFileTestManagementTool);
232
+ server.tool("createTestCasesFromFile", "Create test cases from a file in BrowserStack Test Management.", CreateTestCasesFromFileSchema.shape, createTestCasesFromFileTool);
164
233
  }
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "@browserstack/mcp-server",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "BrowserStack's Official MCP Server",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/browserstack/mcp-server.git"
9
9
  },
10
+ "type": "module",
10
11
  "scripts": {
11
12
  "build": "npm run lint && npm run format && npm test && tsc",
12
13
  "start": "node dist/index.js",
13
14
  "dev": "tsx watch --clear-screen=false src/index.ts",
14
- "test": "jest",
15
+ "test": "vitest run",
15
16
  "lint": "eslint . --ext .ts",
16
17
  "format": "prettier --write \"src/**/*.ts\""
17
18
  },
@@ -41,18 +42,21 @@
41
42
  "form-data": "^4.0.2",
42
43
  "pino": "^9.6.0",
43
44
  "pino-pretty": "^13.0.0",
45
+ "sharp": "^0.34.1",
46
+ "uuid": "^11.1.0",
47
+ "webdriverio": "^9.13.0",
44
48
  "zod": "^3.24.3"
45
49
  },
46
50
  "devDependencies": {
47
51
  "@eslint/js": "^9.25.0",
48
- "@types/jest": "^29.5.14",
49
52
  "@types/node": "^22.14.1",
53
+ "@types/uuid": "^10.0.0",
50
54
  "eslint": "^9.25.0",
51
- "jest": "^29.7.0",
52
55
  "prettier": "^3.5.3",
53
- "ts-jest": "^29.3.2",
54
56
  "tsx": "^4.19.3",
55
57
  "typescript": "^5.8.3",
56
- "typescript-eslint": "^8.30.1"
58
+ "typescript-eslint": "^8.30.1",
59
+ "vite": "^6.3.5",
60
+ "vitest": "^3.1.3"
57
61
  }
58
62
  }