@browserstack/mcp-server 1.0.8 → 1.0.10

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.
@@ -0,0 +1,64 @@
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.SUPPORTED_CONFIGURATIONS = void 0;
7
+ const config_1 = __importDefault(require("../../config"));
8
+ const nodejsInstructions = `
9
+ - Ensure that \`browserstack-node-sdk\` is present in package.json, use the latest version.
10
+ - Add new scripts to package.json for running tests on BrowserStack (use \`npx\` to trigger the sdk):
11
+ \`\`\`json
12
+ "scripts": {
13
+ "test:browserstack": "npx browserstack-node-sdk <framework-specific-test-execution-command>"
14
+ }
15
+ \`\`\`
16
+ - Add to dependencies:
17
+ \`\`\`json
18
+ "browserstack-node-sdk": "latest"
19
+ \`\`\`
20
+ - Inform user to export BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY as environment variables.
21
+ `;
22
+ const pythonInstructions = `
23
+ Run the following command to install the browserstack-sdk:
24
+ \`\`\`bash
25
+ python3 -m pip install browserstack-sdk
26
+ \`\`\`
27
+
28
+ Run the following command to setup the browserstack-sdk:
29
+ \`\`\`bash
30
+ browserstack-sdk setup --username "${config_1.default.browserstackUsername}" --key "${config_1.default.browserstackAccessKey}"
31
+ \`\`\`
32
+
33
+ In order to run tests on BrowserStack, run the following command:
34
+ \`\`\`bash
35
+ browserstack-sdk python <path-to-test-file>
36
+ \`\`\`
37
+ `;
38
+ exports.SUPPORTED_CONFIGURATIONS = {
39
+ nodejs: {
40
+ playwright: {
41
+ jest: { instructions: nodejsInstructions },
42
+ codeceptjs: { instructions: nodejsInstructions },
43
+ playwright: { instructions: nodejsInstructions },
44
+ },
45
+ selenium: {
46
+ jest: { instructions: nodejsInstructions },
47
+ webdriverio: { instructions: nodejsInstructions },
48
+ mocha: { instructions: nodejsInstructions },
49
+ cucumber: { instructions: nodejsInstructions },
50
+ nightwatch: { instructions: nodejsInstructions },
51
+ codeceptjs: { instructions: nodejsInstructions },
52
+ },
53
+ },
54
+ python: {
55
+ playwright: {
56
+ pytest: { instructions: pythonInstructions },
57
+ },
58
+ selenium: {
59
+ pytest: { instructions: pythonInstructions },
60
+ robot: { instructions: pythonInstructions },
61
+ behave: { instructions: pythonInstructions },
62
+ },
63
+ },
64
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getInstructionsForProjectConfiguration = void 0;
4
+ exports.generateBrowserStackYMLInstructions = generateBrowserStackYMLInstructions;
5
+ const constants_1 = require("./constants");
6
+ const errorMessageSuffix = "Please open an issue at our Github repo: https://github.com/browserstack/browserstack-mcp-server/issues to request support for your project configuration";
7
+ const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage) => {
8
+ const configuration = constants_1.SUPPORTED_CONFIGURATIONS[detectedLanguage];
9
+ if (!configuration) {
10
+ throw new Error(`BrowserStack MCP Server currently does not support ${detectedLanguage}, ${errorMessageSuffix}`);
11
+ }
12
+ if (!configuration[detectedBrowserAutomationFramework]) {
13
+ throw new Error(`BrowserStack MCP Server currently does not support ${detectedBrowserAutomationFramework} for ${detectedLanguage}, ${errorMessageSuffix}`);
14
+ }
15
+ if (!configuration[detectedBrowserAutomationFramework][detectedTestingFramework]) {
16
+ throw new Error(`BrowserStack MCP Server currently does not support ${detectedTestingFramework} for ${detectedBrowserAutomationFramework} on ${detectedLanguage}, ${errorMessageSuffix}`);
17
+ }
18
+ return configuration[detectedBrowserAutomationFramework][detectedTestingFramework].instructions;
19
+ };
20
+ exports.getInstructionsForProjectConfiguration = getInstructionsForProjectConfiguration;
21
+ function generateBrowserStackYMLInstructions(desiredPlatforms) {
22
+ return `
23
+ Create a browserstack.yml file in the project root. The file should be in the following format:
24
+
25
+ \`\`\`yaml
26
+ # ======================
27
+ # BrowserStack Reporting
28
+ # ======================
29
+ projectName: BrowserStack MCP Runs
30
+ build: mcp-run
31
+
32
+ # =======================================
33
+ # Platforms (Browsers / Devices to test)
34
+ # =======================================
35
+ # Platforms object contains all the browser / device combinations you want to test on.
36
+ # Generate this on the basis of the following platforms requested by the user:
37
+ # Requested platforms: ${desiredPlatforms}
38
+ platforms:
39
+ - os: Windows
40
+ osVersion: 11
41
+ browserName: chrome
42
+ browserVersion: latest
43
+
44
+ # =======================
45
+ # Parallels per Platform
46
+ # =======================
47
+ # The number of parallel threads to be used for each platform set.
48
+ # BrowserStack's SDK runner will select the best strategy based on the configured value
49
+ #
50
+ # Example 1 - If you have configured 3 platforms and set \`parallelsPerPlatform\` as 2, a total of 6 (2 * 3) parallel threads will be used on BrowserStack
51
+ #
52
+ # Example 2 - If you have configured 1 platform and set \`parallelsPerPlatform\` as 5, a total of 5 (1 * 5) parallel threads will be used on BrowserStack
53
+ parallelsPerPlatform: 1
54
+
55
+ browserstackLocal: true
56
+
57
+ # ===================
58
+ # Debugging features
59
+ # ===================
60
+ debug: true
61
+ testObservability: true
62
+ \`\`\`
63
+ \n`;
64
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,107 @@
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.CreateProjFoldSchema = void 0;
7
+ exports.createProjectOrFolder = createProjectOrFolder;
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const config_1 = __importDefault(require("../../config"));
10
+ const zod_1 = require("zod");
11
+ const error_1 = require("../../lib/error"); // or correct path
12
+ // Schema for combined project/folder creation
13
+ exports.CreateProjFoldSchema = zod_1.z.object({
14
+ project_name: zod_1.z
15
+ .string()
16
+ .optional()
17
+ .describe("Name of the project to create."),
18
+ project_description: zod_1.z
19
+ .string()
20
+ .optional()
21
+ .describe("Description for the new project."),
22
+ project_identifier: zod_1.z
23
+ .string()
24
+ .optional()
25
+ .describe("Existing project identifier to use for folder creation."),
26
+ folder_name: zod_1.z.string().optional().describe("Name of the folder to create."),
27
+ folder_description: zod_1.z
28
+ .string()
29
+ .optional()
30
+ .describe("Description for the new folder."),
31
+ parent_id: zod_1.z
32
+ .number()
33
+ .optional()
34
+ .describe("Parent folder ID; if omitted, folder is created at root."),
35
+ });
36
+ /**
37
+ * Creates a project and/or folder in BrowserStack Test Management.
38
+ */
39
+ async function createProjectOrFolder(args) {
40
+ const { project_name, project_description, project_identifier, folder_name, folder_description, parent_id, } = exports.CreateProjFoldSchema.parse(args);
41
+ if (!project_name && !project_identifier && !folder_name) {
42
+ throw new Error("Provide project_name (to create project), or project_identifier and folder_name (to create folder).");
43
+ }
44
+ let projId = project_identifier;
45
+ // Step 1: Create project if project_name provided
46
+ if (project_name) {
47
+ try {
48
+ const res = await axios_1.default.post("https://test-management.browserstack.com/api/v2/projects", { project: { name: project_name, description: project_description } }, {
49
+ auth: {
50
+ username: config_1.default.browserstackUsername,
51
+ password: config_1.default.browserstackAccessKey,
52
+ },
53
+ headers: { "Content-Type": "application/json" },
54
+ });
55
+ if (!res.data.success) {
56
+ throw new Error(`Failed to create project: ${JSON.stringify(res.data)}`);
57
+ }
58
+ // Project created successfully
59
+ projId = res.data.project.identifier;
60
+ }
61
+ catch (err) {
62
+ return (0, error_1.formatAxiosError)(err, "Failed to create project..");
63
+ }
64
+ }
65
+ // Step 2: Create folder if folder_name provided
66
+ if (folder_name) {
67
+ if (!projId)
68
+ throw new Error("Cannot create folder without project_identifier.");
69
+ try {
70
+ const res = await axios_1.default.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(projId)}/folders`, {
71
+ folder: {
72
+ name: folder_name,
73
+ description: folder_description,
74
+ parent_id,
75
+ },
76
+ }, {
77
+ auth: {
78
+ username: config_1.default.browserstackUsername,
79
+ password: config_1.default.browserstackAccessKey,
80
+ },
81
+ headers: { "Content-Type": "application/json" },
82
+ });
83
+ if (!res.data.success) {
84
+ throw new Error(`Failed to create folder: ${JSON.stringify(res.data)}`);
85
+ }
86
+ // Folder created successfully
87
+ const folder = res.data.folder;
88
+ return {
89
+ content: [
90
+ {
91
+ type: "text",
92
+ text: `Folder created: ID=${folder.id}, name=${folder.name} in project with identifier ${projId}`,
93
+ },
94
+ ],
95
+ };
96
+ }
97
+ catch (err) {
98
+ return (0, error_1.formatAxiosError)(err, "Failed to create folder.");
99
+ }
100
+ }
101
+ // Only project was created
102
+ return {
103
+ content: [
104
+ { type: "text", text: `Project created with identifier=${projId}` },
105
+ ],
106
+ };
107
+ }
@@ -0,0 +1,115 @@
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.CreateTestCaseSchema = void 0;
7
+ exports.sanitizeArgs = sanitizeArgs;
8
+ exports.createTestCase = createTestCase;
9
+ const axios_1 = __importDefault(require("axios"));
10
+ const config_1 = __importDefault(require("../../config"));
11
+ const zod_1 = require("zod");
12
+ const error_1 = require("../../lib/error"); // or correct
13
+ exports.CreateTestCaseSchema = zod_1.z.object({
14
+ project_identifier: zod_1.z
15
+ .string()
16
+ .describe("The ID of the BrowserStack project where the test case should be created. If no project identifier is provided, ask the user if they would like to create a new project using the createProjectOrFolder tool."),
17
+ folder_id: zod_1.z
18
+ .string()
19
+ .describe("The ID of the folder within the project where the test case should be created. If not provided, ask the user if they would like to create a new folder using the createProjectOrFolder tool."),
20
+ name: zod_1.z.string().describe("Name of the test case."),
21
+ description: zod_1.z
22
+ .string()
23
+ .optional()
24
+ .describe("Brief description of the test case."),
25
+ owner: zod_1.z
26
+ .string()
27
+ .email()
28
+ .describe("Email of the test case owner.")
29
+ .optional(),
30
+ preconditions: zod_1.z
31
+ .string()
32
+ .optional()
33
+ .describe("Any preconditions (HTML allowed)."),
34
+ test_case_steps: zod_1.z
35
+ .array(zod_1.z.object({
36
+ step: zod_1.z.string().describe("Action to perform in this step."),
37
+ result: zod_1.z.string().describe("Expected result of this step."),
38
+ }))
39
+ .describe("List of steps and expected results."),
40
+ issues: zod_1.z
41
+ .array(zod_1.z.string())
42
+ .optional()
43
+ .describe("List of the linked Jira, Asana or Azure issues ID's. This should be strictly in array format not the string of json."),
44
+ issue_tracker: zod_1.z
45
+ .object({
46
+ name: zod_1.z
47
+ .string()
48
+ .describe("Issue tracker name, For example, use jira for Jira, azure for Azure DevOps, or asana for Asana."),
49
+ host: zod_1.z.string().url().describe("Base URL of the issue tracker."),
50
+ })
51
+ .optional(),
52
+ tags: zod_1.z
53
+ .array(zod_1.z.string())
54
+ .optional()
55
+ .describe("Tags to attach to the test case. This should be strictly in array format not the string of json"),
56
+ custom_fields: zod_1.z
57
+ .record(zod_1.z.string(), zod_1.z.string())
58
+ .optional()
59
+ .describe("Map of custom field names to values."),
60
+ });
61
+ function sanitizeArgs(args) {
62
+ const cleaned = { ...args };
63
+ if (cleaned.description === null)
64
+ delete cleaned.description;
65
+ if (cleaned.owner === null)
66
+ delete cleaned.owner;
67
+ if (cleaned.preconditions === null)
68
+ delete cleaned.preconditions;
69
+ if (cleaned.issue_tracker) {
70
+ if (cleaned.issue_tracker.name === undefined ||
71
+ cleaned.issue_tracker.host === undefined) {
72
+ delete cleaned.issue_tracker;
73
+ }
74
+ }
75
+ return cleaned;
76
+ }
77
+ async function createTestCase(params) {
78
+ const body = { test_case: params };
79
+ try {
80
+ const response = await axios_1.default.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(params.project_identifier)}/folders/${encodeURIComponent(params.folder_id)}/test-cases`, body, {
81
+ auth: {
82
+ username: config_1.default.browserstackUsername,
83
+ password: config_1.default.browserstackAccessKey,
84
+ },
85
+ headers: { "Content-Type": "application/json" },
86
+ });
87
+ const { data } = response.data;
88
+ if (!data.success) {
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: `Failed to create test case: ${JSON.stringify(response.data)}`,
94
+ isError: true,
95
+ },
96
+ ],
97
+ isError: true,
98
+ };
99
+ }
100
+ const tc = data.test_case;
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: `Successfully created test case ${tc.identifier}: ${tc.title}`,
106
+ },
107
+ { type: "text", text: JSON.stringify(tc, null, 2) },
108
+ ],
109
+ };
110
+ }
111
+ catch (err) {
112
+ // Delegate to our centralized Axios error formatter
113
+ return (0, error_1.formatAxiosError)(err, "Failed to create test case");
114
+ }
115
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createProjectOrFolderTool = createProjectOrFolderTool;
4
+ exports.createTestCaseTool = createTestCaseTool;
5
+ exports.default = addTestManagementTools;
6
+ const create_project_folder_1 = require("./testmanagement-utils/create-project-folder");
7
+ const create_testcase_1 = require("./testmanagement-utils/create-testcase");
8
+ /**
9
+ * Wrapper to call createProjectOrFolder util.
10
+ */
11
+ async function createProjectOrFolderTool(args) {
12
+ try {
13
+ return await (0, create_project_folder_1.createProjectOrFolder)(args);
14
+ }
15
+ catch (err) {
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: `Failed to create project/folder: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
21
+ isError: true,
22
+ },
23
+ ],
24
+ isError: true,
25
+ };
26
+ }
27
+ }
28
+ /**
29
+ * Creates a test case in BrowserStack Test Management.
30
+ */
31
+ async function createTestCaseTool(args) {
32
+ // Sanitize input arguments
33
+ const cleanedArgs = (0, create_testcase_1.sanitizeArgs)(args);
34
+ try {
35
+ return await (0, create_testcase_1.createTestCase)(cleanedArgs);
36
+ }
37
+ catch (err) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `Failed to create test case: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
43
+ isError: true,
44
+ },
45
+ ],
46
+ isError: true,
47
+ };
48
+ }
49
+ }
50
+ /**
51
+ * Registers both project/folder and test-case tools.
52
+ */
53
+ function addTestManagementTools(server) {
54
+ server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management.", create_project_folder_1.CreateProjFoldSchema.shape, createProjectOrFolderTool);
55
+ server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management.", create_testcase_1.CreateTestCaseSchema.shape, createTestCaseTool);
56
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserstack/mcp-server",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "BrowserStack's Official MCP Server",
5
5
  "main": "dist/index.js",
6
6
  "repository": {