@browserstack/mcp-server 1.1.0 → 1.1.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 (53) hide show
  1. package/dist/config.js +2 -6
  2. package/dist/index.js +29 -34
  3. package/dist/lib/api.js +3 -9
  4. package/dist/lib/constants.js +3 -6
  5. package/dist/lib/device-cache.js +14 -21
  6. package/dist/lib/error.js +3 -6
  7. package/dist/lib/fuzzy.js +1 -4
  8. package/dist/lib/inmemory-store.js +1 -4
  9. package/dist/lib/instrumentation.js +12 -18
  10. package/dist/lib/local.js +27 -35
  11. package/dist/lib/utils.js +6 -15
  12. package/dist/logger.js +4 -6
  13. package/dist/tools/accessibility.js +13 -16
  14. package/dist/tools/accessiblity-utils/report-fetcher.js +7 -14
  15. package/dist/tools/accessiblity-utils/report-parser.js +5 -11
  16. package/dist/tools/accessiblity-utils/scanner.js +9 -16
  17. package/dist/tools/appautomate-utils/appautomate.js +17 -27
  18. package/dist/tools/appautomate.js +29 -35
  19. package/dist/tools/applive-utils/fuzzy-search.js +3 -6
  20. package/dist/tools/applive-utils/start-session.js +14 -20
  21. package/dist/tools/applive-utils/upload-app.js +12 -51
  22. package/dist/tools/applive.js +18 -25
  23. package/dist/tools/automate-utils/fetch-screenshots.js +8 -14
  24. package/dist/tools/automate.js +14 -21
  25. package/dist/tools/bstack-sdk.js +14 -18
  26. package/dist/tools/failurelogs-utils/app-automate.js +15 -26
  27. package/dist/tools/failurelogs-utils/automate.js +13 -23
  28. package/dist/tools/getFailureLogs.js +42 -49
  29. package/dist/tools/live-utils/desktop-filter.js +8 -11
  30. package/dist/tools/live-utils/mobile-filter.js +7 -10
  31. package/dist/tools/live-utils/start-session.js +17 -23
  32. package/dist/tools/live-utils/types.js +2 -5
  33. package/dist/tools/live-utils/version-resolver.js +1 -4
  34. package/dist/tools/live.js +23 -29
  35. package/dist/tools/observability.js +12 -19
  36. package/dist/tools/sdk-utils/constants.js +3 -9
  37. package/dist/tools/sdk-utils/instructions.js +4 -9
  38. package/dist/tools/sdk-utils/types.js +1 -2
  39. package/dist/tools/testmanagement-utils/TCG-utils/api.js +26 -38
  40. package/dist/tools/testmanagement-utils/TCG-utils/config.js +5 -10
  41. package/dist/tools/testmanagement-utils/TCG-utils/helpers.js +3 -8
  42. package/dist/tools/testmanagement-utils/TCG-utils/types.js +5 -8
  43. package/dist/tools/testmanagement-utils/add-test-result.js +17 -24
  44. package/dist/tools/testmanagement-utils/create-project-folder.js +21 -28
  45. package/dist/tools/testmanagement-utils/create-testcase.js +30 -38
  46. package/dist/tools/testmanagement-utils/create-testrun.js +23 -30
  47. package/dist/tools/testmanagement-utils/list-testcases.js +15 -22
  48. package/dist/tools/testmanagement-utils/list-testruns.js +12 -19
  49. package/dist/tools/testmanagement-utils/testcase-from-file.js +16 -22
  50. package/dist/tools/testmanagement-utils/update-testrun.js +15 -22
  51. package/dist/tools/testmanagement-utils/upload-file.js +22 -29
  52. package/dist/tools/testmanagement.js +61 -76
  53. package/package.json +1 -1
package/dist/config.js CHANGED
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Config = void 0;
4
1
  if (!process.env.BROWSERSTACK_ACCESS_KEY ||
5
2
  !process.env.BROWSERSTACK_USERNAME) {
6
3
  throw new Error("Unable to start MCP server. Please set the BROWSERSTACK_ACCESS_KEY and BROWSERSTACK_USERNAME environment variables. Go to https://www.browserstack.com/accounts/profile/details to access them");
7
4
  }
8
- class Config {
5
+ export class Config {
9
6
  browserstackUsername;
10
7
  browserstackAccessKey;
11
8
  DEV_MODE;
@@ -15,6 +12,5 @@ class Config {
15
12
  this.DEV_MODE = DEV_MODE;
16
13
  }
17
14
  }
18
- exports.Config = Config;
19
15
  const config = new Config(process.env.BROWSERSTACK_USERNAME, process.env.BROWSERSTACK_ACCESS_KEY, process.env.DEV_MODE === "true");
20
- exports.default = config;
16
+ export default config;
package/dist/index.js CHANGED
@@ -1,49 +1,44 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
8
- const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
- const package_json_1 = __importDefault(require("../package.json"));
10
- require("dotenv/config");
11
- const logger_js_1 = __importDefault(require("./logger.js"));
12
- const bstack_sdk_js_1 = __importDefault(require("./tools/bstack-sdk.js"));
13
- const applive_js_1 = __importDefault(require("./tools/applive.js"));
14
- const live_js_1 = __importDefault(require("./tools/live.js"));
15
- const accessibility_js_1 = __importDefault(require("./tools/accessibility.js"));
16
- const testmanagement_js_1 = __importDefault(require("./tools/testmanagement.js"));
17
- const appautomate_js_1 = __importDefault(require("./tools/appautomate.js"));
18
- const getFailureLogs_js_1 = __importDefault(require("./tools/getFailureLogs.js"));
19
- const automate_js_1 = __importDefault(require("./tools/automate.js"));
20
- const instrumentation_js_1 = require("./lib/instrumentation.js");
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import packageJson from "../package.json" with { type: "json" };
5
+ import "dotenv/config";
6
+ import logger from "./logger.js";
7
+ import addSDKTools from "./tools/bstack-sdk.js";
8
+ import addAppLiveTools from "./tools/applive.js";
9
+ import addBrowserLiveTools from "./tools/live.js";
10
+ import addAccessibilityTools from "./tools/accessibility.js";
11
+ import addTestManagementTools from "./tools/testmanagement.js";
12
+ import addAppAutomationTools from "./tools/appautomate.js";
13
+ import addFailureLogsTools from "./tools/getFailureLogs.js";
14
+ import addAutomateTools from "./tools/automate.js";
15
+ import { trackMCP } from "./lib/instrumentation.js";
21
16
  function registerTools(server) {
22
- (0, bstack_sdk_js_1.default)(server);
23
- (0, applive_js_1.default)(server);
24
- (0, live_js_1.default)(server);
25
- (0, accessibility_js_1.default)(server);
26
- (0, testmanagement_js_1.default)(server);
27
- (0, appautomate_js_1.default)(server);
28
- (0, getFailureLogs_js_1.default)(server);
29
- (0, automate_js_1.default)(server);
17
+ addSDKTools(server);
18
+ addAppLiveTools(server);
19
+ addBrowserLiveTools(server);
20
+ addAccessibilityTools(server);
21
+ addTestManagementTools(server);
22
+ addAppAutomationTools(server);
23
+ addFailureLogsTools(server);
24
+ addAutomateTools(server);
30
25
  }
31
26
  // Create an MCP server
32
- const server = new mcp_js_1.McpServer({
27
+ const server = new McpServer({
33
28
  name: "BrowserStack MCP Server",
34
- version: package_json_1.default.version,
29
+ version: packageJson.version,
35
30
  });
36
31
  registerTools(server);
37
32
  async function main() {
38
- logger_js_1.default.info("Launching BrowserStack MCP server, version %s", package_json_1.default.version);
33
+ logger.info("Launching BrowserStack MCP server, version %s", packageJson.version);
39
34
  // Start receiving messages on stdin and sending messages on stdout
40
- const transport = new stdio_js_1.StdioServerTransport();
35
+ const transport = new StdioServerTransport();
41
36
  await server.connect(transport);
42
- logger_js_1.default.info("MCP server started successfully");
43
- (0, instrumentation_js_1.trackMCP)("started", server.server.getClientVersion());
37
+ logger.info("MCP server started successfully");
38
+ trackMCP("started", server.server.getClientVersion());
44
39
  }
45
40
  main().catch(console.error);
46
41
  // Ensure logs are flushed before exit
47
42
  process.on("exit", () => {
48
- logger_js_1.default.flush();
43
+ logger.flush();
49
44
  });
package/dist/lib/api.js CHANGED
@@ -1,15 +1,9 @@
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.getLatestO11YBuildInfo = getLatestO11YBuildInfo;
7
- const config_js_1 = __importDefault(require("../config.js"));
8
- async function getLatestO11YBuildInfo(buildName, projectName) {
1
+ import config from "../config.js";
2
+ export async function getLatestO11YBuildInfo(buildName, projectName) {
9
3
  const buildsUrl = `https://api-observability.browserstack.com/ext/v1/builds/latest?build_name=${encodeURIComponent(buildName)}&project_name=${encodeURIComponent(projectName)}`;
10
4
  const buildsResponse = await fetch(buildsUrl, {
11
5
  headers: {
12
- Authorization: `Basic ${Buffer.from(`${config_js_1.default.browserstackUsername}:${config_js_1.default.browserstackAccessKey}`).toString("base64")}`,
6
+ Authorization: `Basic ${Buffer.from(`${config.browserstackUsername}:${config.browserstackAccessKey}`).toString("base64")}`,
13
7
  },
14
8
  });
15
9
  if (!buildsResponse.ok) {
@@ -1,16 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AppAutomateLogType = exports.AutomateLogType = exports.SessionType = void 0;
4
- exports.SessionType = {
1
+ export const SessionType = {
5
2
  Automate: "automate",
6
3
  AppAutomate: "app-automate",
7
4
  };
8
- exports.AutomateLogType = {
5
+ export const AutomateLogType = {
9
6
  NetworkLogs: "networkLogs",
10
7
  SessionLogs: "sessionLogs",
11
8
  ConsoleLogs: "consoleLogs",
12
9
  };
13
- exports.AppAutomateLogType = {
10
+ export const AppAutomateLogType = {
14
11
  DeviceLogs: "deviceLogs",
15
12
  AppiumLogs: "appiumLogs",
16
13
  CrashLogs: "crashLogs",
@@ -1,22 +1,15 @@
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.BrowserStackProducts = void 0;
7
- exports.getDevicesAndBrowsers = getDevicesAndBrowsers;
8
- const fs_1 = __importDefault(require("fs"));
9
- const os_1 = __importDefault(require("os"));
10
- const path_1 = __importDefault(require("path"));
11
- const CACHE_DIR = path_1.default.join(os_1.default.homedir(), ".browserstack", "combined_cache");
12
- const CACHE_FILE = path_1.default.join(CACHE_DIR, "data.json");
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+ const CACHE_DIR = path.join(os.homedir(), ".browserstack", "combined_cache");
5
+ const CACHE_FILE = path.join(CACHE_DIR, "data.json");
13
6
  const TTL_MS = 24 * 60 * 60 * 1000; // 1 day
14
- var BrowserStackProducts;
7
+ export var BrowserStackProducts;
15
8
  (function (BrowserStackProducts) {
16
9
  BrowserStackProducts["LIVE"] = "live";
17
10
  BrowserStackProducts["APP_LIVE"] = "app_live";
18
11
  BrowserStackProducts["APP_AUTOMATE"] = "app_automate";
19
- })(BrowserStackProducts || (exports.BrowserStackProducts = BrowserStackProducts = {}));
12
+ })(BrowserStackProducts || (BrowserStackProducts = {}));
20
13
  const URLS = {
21
14
  [BrowserStackProducts.LIVE]: "https://www.browserstack.com/list-of-browsers-and-platforms/live.json",
22
15
  [BrowserStackProducts.APP_LIVE]: "https://www.browserstack.com/list-of-browsers-and-platforms/app_live.json",
@@ -25,16 +18,16 @@ const URLS = {
25
18
  /**
26
19
  * Fetches and caches BrowserStack datasets (live + app_live + app_automate) with a shared TTL.
27
20
  */
28
- async function getDevicesAndBrowsers(type) {
29
- if (!fs_1.default.existsSync(CACHE_DIR)) {
30
- fs_1.default.mkdirSync(CACHE_DIR, { recursive: true });
21
+ export async function getDevicesAndBrowsers(type) {
22
+ if (!fs.existsSync(CACHE_DIR)) {
23
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
31
24
  }
32
25
  let cache = {};
33
- if (fs_1.default.existsSync(CACHE_FILE)) {
34
- const stats = fs_1.default.statSync(CACHE_FILE);
26
+ if (fs.existsSync(CACHE_FILE)) {
27
+ const stats = fs.statSync(CACHE_FILE);
35
28
  if (Date.now() - stats.mtimeMs < TTL_MS) {
36
29
  try {
37
- cache = JSON.parse(fs_1.default.readFileSync(CACHE_FILE, "utf8"));
30
+ cache = JSON.parse(fs.readFileSync(CACHE_FILE, "utf8"));
38
31
  if (cache[type]) {
39
32
  return cache[type];
40
33
  }
@@ -53,6 +46,6 @@ async function getDevicesAndBrowsers(type) {
53
46
  cache = {
54
47
  [type]: data,
55
48
  };
56
- fs_1.default.writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf8");
49
+ fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf8");
57
50
  return cache[type];
58
51
  }
package/dist/lib/error.js CHANGED
@@ -1,15 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatAxiosError = formatAxiosError;
4
- const axios_1 = require("axios");
1
+ import { AxiosError } from "axios";
5
2
  /**
6
3
  * Formats an AxiosError into a CallToolResult with an appropriate message.
7
4
  * @param err - The error object to format
8
5
  * @param defaultText - The fallback error message
9
6
  */
10
- function formatAxiosError(err, defaultText) {
7
+ export function formatAxiosError(err, defaultText) {
11
8
  let text = defaultText;
12
- if (err instanceof axios_1.AxiosError && err.response?.data) {
9
+ if (err instanceof AxiosError && err.response?.data) {
13
10
  const message = err.response.data.message ||
14
11
  err.response.data.error ||
15
12
  err.message ||
package/dist/lib/fuzzy.js CHANGED
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.customFuzzySearch = customFuzzySearch;
4
1
  // 1. Compute Levenshtein distance between two strings
5
2
  function levenshtein(a, b) {
6
3
  const dp = Array(a.length + 1)
@@ -39,7 +36,7 @@ function scoreItem(item, keys, queryTokens) {
39
36
  return best;
40
37
  }
41
38
  // 3. The search entrypoint
42
- function customFuzzySearch(list, keys, query, limit = 5, maxDistance = 0.6) {
39
+ export function customFuzzySearch(list, keys, query, limit = 5, maxDistance = 0.6) {
43
40
  const q = query.toLowerCase().trim();
44
41
  const queryTokens = q.split(/\s+/);
45
42
  return list
@@ -1,4 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.signedUrlMap = void 0;
4
- exports.signedUrlMap = new Map();
1
+ export const signedUrlMap = new Map();
@@ -1,16 +1,10 @@
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.trackMCP = trackMCP;
7
- const logger_js_1 = __importDefault(require("../logger.js"));
8
- const config_js_1 = __importDefault(require("../config.js"));
9
- const package_json_1 = __importDefault(require("../../package.json"));
10
- const axios_1 = __importDefault(require("axios"));
11
- function trackMCP(toolName, clientInfo, error) {
12
- if (config_js_1.default.DEV_MODE) {
13
- logger_js_1.default.info("Tracking MCP is disabled in dev mode");
1
+ import logger from "../logger.js";
2
+ import config from "../config.js";
3
+ import packageJson from "../../package.json" with { type: "json" };
4
+ import axios from "axios";
5
+ export function trackMCP(toolName, clientInfo, error) {
6
+ if (config.DEV_MODE) {
7
+ logger.info("Tracking MCP is disabled in dev mode");
14
8
  return;
15
9
  }
16
10
  const instrumentationEndpoint = "https://api.browserstack.com/sdk/v1/event";
@@ -18,15 +12,15 @@ function trackMCP(toolName, clientInfo, error) {
18
12
  const mcpClient = clientInfo?.name || "unknown";
19
13
  // Log client information
20
14
  if (clientInfo?.name) {
21
- logger_js_1.default.info(`Client connected: ${clientInfo.name} (version: ${clientInfo.version})`);
15
+ logger.info(`Client connected: ${clientInfo.name} (version: ${clientInfo.version})`);
22
16
  }
23
17
  else {
24
- logger_js_1.default.info("Client connected: unknown client");
18
+ logger.info("Client connected: unknown client");
25
19
  }
26
20
  const event = {
27
21
  event_type: "MCPInstrumentation",
28
22
  event_properties: {
29
- mcp_version: package_json_1.default.version,
23
+ mcp_version: packageJson.version,
30
24
  tool_name: toolName,
31
25
  mcp_client: mcpClient,
32
26
  success: isSuccess,
@@ -39,11 +33,11 @@ function trackMCP(toolName, clientInfo, error) {
39
33
  event.event_properties.error_type =
40
34
  error instanceof Error ? error.constructor.name : "Unknown";
41
35
  }
42
- axios_1.default
36
+ axios
43
37
  .post(instrumentationEndpoint, event, {
44
38
  headers: {
45
39
  "Content-Type": "application/json",
46
- Authorization: `Basic ${Buffer.from(`${config_js_1.default.browserstackUsername}:${config_js_1.default.browserstackAccessKey}`).toString("base64")}`,
40
+ Authorization: `Basic ${Buffer.from(`${config.browserstackUsername}:${config.browserstackAccessKey}`).toString("base64")}`,
47
41
  },
48
42
  timeout: 2000,
49
43
  })
package/dist/lib/local.js CHANGED
@@ -1,47 +1,39 @@
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.killExistingBrowserStackLocalProcesses = killExistingBrowserStackLocalProcesses;
7
- exports.ensureLocalBinarySetup = ensureLocalBinarySetup;
8
- exports.isLocalURL = isLocalURL;
9
- const logger_js_1 = __importDefault(require("../logger.js"));
10
- const child_process_1 = require("child_process");
11
- const browserstack_local_1 = require("browserstack-local");
12
- const config_js_1 = __importDefault(require("../config.js"));
1
+ import logger from "../logger.js";
2
+ import { execSync } from "child_process";
3
+ import { Local } from "browserstack-local";
4
+ import config from "../config.js";
13
5
  async function isBrowserStackLocalRunning() {
14
6
  // Check if BrowserStackLocal binary is already running
15
7
  try {
16
8
  if (process.platform === "win32") {
17
- const result = (0, child_process_1.execSync)('tasklist /FI "IMAGENAME eq BrowserStackLocal.exe"', {
9
+ const result = execSync('tasklist /FI "IMAGENAME eq BrowserStackLocal.exe"', {
18
10
  encoding: "utf8",
19
11
  });
20
12
  if (result.includes("BrowserStackLocal.exe")) {
21
- logger_js_1.default.info("BrowserStackLocal binary is already running");
13
+ logger.info("BrowserStackLocal binary is already running");
22
14
  return true;
23
15
  }
24
16
  }
25
17
  else {
26
- const result = (0, child_process_1.execSync)("pgrep -f BrowserStackLocal", {
18
+ const result = execSync("pgrep -f BrowserStackLocal", {
27
19
  encoding: "utf8",
28
20
  stdio: "pipe",
29
21
  }).toString();
30
22
  if (result) {
31
- logger_js_1.default.info("BrowserStackLocal binary is already running");
23
+ logger.info("BrowserStackLocal binary is already running");
32
24
  return true;
33
25
  }
34
26
  }
35
- logger_js_1.default.info("BrowserStackLocal binary is not running");
27
+ logger.info("BrowserStackLocal binary is not running");
36
28
  return false;
37
29
  }
38
30
  catch (error) {
39
- logger_js_1.default.info("Error checking BrowserStackLocal status, assuming not running ... " +
31
+ logger.info("Error checking BrowserStackLocal status, assuming not running ... " +
40
32
  error);
41
33
  return false;
42
34
  }
43
35
  }
44
- async function killExistingBrowserStackLocalProcesses() {
36
+ export async function killExistingBrowserStackLocalProcesses() {
45
37
  const isRunning = await isBrowserStackLocalRunning();
46
38
  if (!isRunning) {
47
39
  return;
@@ -50,50 +42,50 @@ async function killExistingBrowserStackLocalProcesses() {
50
42
  try {
51
43
  if (process.platform === "win32") {
52
44
  // Check if process exists on Windows
53
- const checkResult = (0, child_process_1.execSync)('tasklist /FI "IMAGENAME eq BrowserStackLocal.exe"', { encoding: "utf8" });
45
+ const checkResult = execSync('tasklist /FI "IMAGENAME eq BrowserStackLocal.exe"', { encoding: "utf8" });
54
46
  if (checkResult.includes("BrowserStackLocal.exe")) {
55
- (0, child_process_1.execSync)("taskkill /F /IM BrowserStackLocal.exe", { stdio: "ignore" });
56
- logger_js_1.default.info("Successfully killed existing BrowserStackLocal processes");
47
+ execSync("taskkill /F /IM BrowserStackLocal.exe", { stdio: "ignore" });
48
+ logger.info("Successfully killed existing BrowserStackLocal processes");
57
49
  }
58
50
  }
59
51
  else {
60
52
  // Check if process exists on Unix-like systems
61
- const checkResult = (0, child_process_1.execSync)("pgrep -f BrowserStackLocal", {
53
+ const checkResult = execSync("pgrep -f BrowserStackLocal", {
62
54
  encoding: "utf8",
63
55
  stdio: "pipe",
64
56
  }).toString();
65
57
  if (checkResult) {
66
- (0, child_process_1.execSync)("pkill -f BrowserStackLocal", { stdio: "ignore" });
67
- logger_js_1.default.info("Successfully killed existing BrowserStackLocal processes");
58
+ execSync("pkill -f BrowserStackLocal", { stdio: "ignore" });
59
+ logger.info("Successfully killed existing BrowserStackLocal processes");
68
60
  }
69
61
  }
70
62
  }
71
63
  catch (error) {
72
- logger_js_1.default.info(`Error checking/killing BrowserStackLocal processes: ${error}`);
64
+ logger.info(`Error checking/killing BrowserStackLocal processes: ${error}`);
73
65
  // Continue execution as there may not be any processes running
74
66
  }
75
67
  }
76
- async function ensureLocalBinarySetup() {
77
- logger_js_1.default.info("Ensuring local binary setup as it is required for private URLs...");
78
- const localBinary = new browserstack_local_1.Local();
68
+ export async function ensureLocalBinarySetup() {
69
+ logger.info("Ensuring local binary setup as it is required for private URLs...");
70
+ const localBinary = new Local();
79
71
  await killExistingBrowserStackLocalProcesses();
80
72
  return await new Promise((resolve, reject) => {
81
73
  localBinary.start({
82
- key: config_js_1.default.browserstackAccessKey,
83
- username: config_js_1.default.browserstackUsername,
74
+ key: config.browserstackAccessKey,
75
+ username: config.browserstackUsername,
84
76
  }, (error) => {
85
77
  if (error) {
86
- logger_js_1.default.error(`Unable to start BrowserStack Local... please check your credentials and try again. Error: ${error}`);
78
+ logger.error(`Unable to start BrowserStack Local... please check your credentials and try again. Error: ${error}`);
87
79
  reject(new Error(`Unable to configure local tunnel binary, please check your credentials and try again. Error: ${error}`));
88
80
  }
89
81
  else {
90
- logger_js_1.default.info("Successfully started BrowserStack Local");
82
+ logger.info("Successfully started BrowserStack Local");
91
83
  resolve();
92
84
  }
93
85
  });
94
86
  });
95
87
  }
96
- function isLocalURL(url) {
88
+ export function isLocalURL(url) {
97
89
  try {
98
90
  const urlObj = new URL(url);
99
91
  const hostname = urlObj.hostname.toLowerCase();
@@ -103,7 +95,7 @@ function isLocalURL(url) {
103
95
  hostname.endsWith(".localhost"));
104
96
  }
105
97
  catch (error) {
106
- logger_js_1.default.error(`Error checking if URL is local: ${error}`);
98
+ logger.error(`Error checking if URL is local: ${error}`);
107
99
  return false;
108
100
  }
109
101
  }
package/dist/lib/utils.js CHANGED
@@ -1,20 +1,11 @@
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.sanitizeUrlParam = sanitizeUrlParam;
7
- exports.maybeCompressBase64 = maybeCompressBase64;
8
- exports.assertOkResponse = assertOkResponse;
9
- exports.filterLinesByKeywords = filterLinesByKeywords;
10
- const sharp_1 = __importDefault(require("sharp"));
11
- function sanitizeUrlParam(param) {
1
+ import sharp from "sharp";
2
+ export function sanitizeUrlParam(param) {
12
3
  // Remove any characters that could be used for command injection
13
4
  return param.replace(/[;&|`$(){}[\]<>]/g, "");
14
5
  }
15
6
  const ONE_MB = 1048576;
16
7
  //Compresses a base64 image intelligently to keep it under 1 MB if needed.
17
- async function maybeCompressBase64(base64) {
8
+ export async function maybeCompressBase64(base64) {
18
9
  const buffer = Buffer.from(base64, "base64");
19
10
  if (buffer.length <= ONE_MB) {
20
11
  return base64;
@@ -22,10 +13,10 @@ async function maybeCompressBase64(base64) {
22
13
  const sizeRatio = 1048576 / buffer.length;
23
14
  const estimatedQuality = Math.floor(sizeRatio * 100);
24
15
  const quality = Math.min(95, Math.max(30, estimatedQuality));
25
- const compressedBuffer = await (0, sharp_1.default)(buffer).png({ quality }).toBuffer();
16
+ const compressedBuffer = await sharp(buffer).png({ quality }).toBuffer();
26
17
  return compressedBuffer.toString("base64");
27
18
  }
28
- async function assertOkResponse(response, action) {
19
+ export async function assertOkResponse(response, action) {
29
20
  if (!response.ok) {
30
21
  if (response.status === 404) {
31
22
  throw new Error(`Invalid session ID for ${action}`);
@@ -33,7 +24,7 @@ async function assertOkResponse(response, action) {
33
24
  throw new Error(`Failed to fetch logs for ${action}: ${response.statusText}`);
34
25
  }
35
26
  }
36
- function filterLinesByKeywords(logText, keywords) {
27
+ export function filterLinesByKeywords(logText, keywords) {
37
28
  return logText
38
29
  .split(/\r?\n/)
39
30
  .map((line) => line.trim())
package/dist/logger.js CHANGED
@@ -1,9 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const pino_1 = require("pino");
1
+ import { pino } from "pino";
4
2
  let logger;
5
3
  if (process.env.NODE_ENV === "development") {
6
- logger = (0, pino_1.pino)({
4
+ logger = pino({
7
5
  level: "debug",
8
6
  transport: {
9
7
  targets: [
@@ -24,7 +22,7 @@ if (process.env.NODE_ENV === "development") {
24
22
  }
25
23
  else {
26
24
  // NULL logger
27
- logger = (0, pino_1.pino)({
25
+ logger = pino({
28
26
  level: "info",
29
27
  transport: {
30
28
  target: "pino/file",
@@ -34,4 +32,4 @@ else {
34
32
  },
35
33
  });
36
34
  }
37
- exports.default = logger;
35
+ export default logger;
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = addAccessibilityTools;
4
- const zod_1 = require("zod");
5
- const scanner_js_1 = require("./accessiblity-utils/scanner.js");
6
- const report_fetcher_js_1 = require("./accessiblity-utils/report-fetcher.js");
7
- const instrumentation_js_1 = require("../lib/instrumentation.js");
8
- const report_parser_js_1 = require("./accessiblity-utils/report-parser.js");
9
- const scanner = new scanner_js_1.AccessibilityScanner();
10
- const reportFetcher = new report_fetcher_js_1.AccessibilityReportFetcher();
1
+ import { z } from "zod";
2
+ import { AccessibilityScanner } from "./accessiblity-utils/scanner.js";
3
+ import { AccessibilityReportFetcher } from "./accessiblity-utils/report-fetcher.js";
4
+ import { trackMCP } from "../lib/instrumentation.js";
5
+ import { parseAccessibilityReportFromCSV } from "./accessiblity-utils/report-parser.js";
6
+ const scanner = new AccessibilityScanner();
7
+ const reportFetcher = new AccessibilityReportFetcher();
11
8
  async function runAccessibilityScan(name, pageURL, context) {
12
9
  // Start scan
13
10
  const startResp = await scanner.startScan(name, [pageURL]);
@@ -39,7 +36,7 @@ async function runAccessibilityScan(name, pageURL, context) {
39
36
  }
40
37
  // Fetch CSV report link
41
38
  const reportLink = await reportFetcher.getReportLink(scanId, scanRunId);
42
- const { records } = await (0, report_parser_js_1.parseAccessibilityReportFromCSV)(reportLink);
39
+ const { records } = await parseAccessibilityReportFromCSV(reportLink);
43
40
  return {
44
41
  content: [
45
42
  {
@@ -53,17 +50,17 @@ async function runAccessibilityScan(name, pageURL, context) {
53
50
  ],
54
51
  };
55
52
  }
56
- function addAccessibilityTools(server) {
53
+ export default function addAccessibilityTools(server) {
57
54
  server.tool("startAccessibilityScan", "Start an accessibility scan via BrowserStack and retrieve a local CSV report path.", {
58
- name: zod_1.z.string().describe("Name of the accessibility scan"),
59
- pageURL: zod_1.z.string().describe("The URL to scan for accessibility issues"),
55
+ name: z.string().describe("Name of the accessibility scan"),
56
+ pageURL: z.string().describe("The URL to scan for accessibility issues"),
60
57
  }, async (args, context) => {
61
58
  try {
62
- (0, instrumentation_js_1.trackMCP)("startAccessibilityScan", server.server.getClientVersion());
59
+ trackMCP("startAccessibilityScan", server.server.getClientVersion());
63
60
  return await runAccessibilityScan(args.name, args.pageURL, context);
64
61
  }
65
62
  catch (error) {
66
- (0, instrumentation_js_1.trackMCP)("startAccessibilityScan", server.server.getClientVersion(), error);
63
+ trackMCP("startAccessibilityScan", server.server.getClientVersion(), error);
67
64
  return {
68
65
  content: [
69
66
  {
@@ -1,20 +1,14 @@
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.AccessibilityReportFetcher = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- const config_js_1 = __importDefault(require("../../config.js"));
9
- class AccessibilityReportFetcher {
1
+ import axios from "axios";
2
+ import config from "../../config.js";
3
+ export class AccessibilityReportFetcher {
10
4
  auth = {
11
- username: config_js_1.default.browserstackUsername,
12
- password: config_js_1.default.browserstackAccessKey,
5
+ username: config.browserstackUsername,
6
+ password: config.browserstackAccessKey,
13
7
  };
14
8
  async getReportLink(scanId, scanRunId) {
15
9
  // Initiate CSV link generation
16
10
  const initUrl = `https://api-accessibility.browserstack.com/api/website-scanner/v1/scans/${scanId}/scan_runs/issues?scan_run_id=${scanRunId}`;
17
- const initResp = await axios_1.default.get(initUrl, {
11
+ const initResp = await axios.get(initUrl, {
18
12
  auth: this.auth,
19
13
  });
20
14
  if (!initResp.data.success) {
@@ -23,7 +17,7 @@ class AccessibilityReportFetcher {
23
17
  const taskId = initResp.data.data.task_id;
24
18
  // Fetch the generated CSV link
25
19
  const reportUrl = `https://api-accessibility.browserstack.com/api/website-scanner/v1/scans/${scanId}/scan_runs/issues?task_id=${encodeURIComponent(taskId)}`;
26
- const reportResp = await axios_1.default.get(reportUrl, {
20
+ const reportResp = await axios.get(reportUrl, {
27
21
  auth: this.auth,
28
22
  });
29
23
  if (!reportResp.data.success) {
@@ -32,4 +26,3 @@ class AccessibilityReportFetcher {
32
26
  return reportResp.data.data.reportLink;
33
27
  }
34
28
  }
35
- exports.AccessibilityReportFetcher = AccessibilityReportFetcher;
@@ -1,18 +1,12 @@
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.parseAccessibilityReportFromCSV = parseAccessibilityReportFromCSV;
7
- const node_fetch_1 = __importDefault(require("node-fetch"));
8
- const sync_1 = require("csv-parse/sync");
9
- async function parseAccessibilityReportFromCSV(reportLink, { maxCharacterLength = 10_000, nextPage = 0 } = {}) {
1
+ import fetch from "node-fetch";
2
+ import { parse } from "csv-parse/sync";
3
+ export async function parseAccessibilityReportFromCSV(reportLink, { maxCharacterLength = 10_000, nextPage = 0 } = {}) {
10
4
  // 1) Download & parse
11
- const res = await (0, node_fetch_1.default)(reportLink);
5
+ const res = await fetch(reportLink);
12
6
  if (!res.ok)
13
7
  throw new Error(`Failed to download report: ${res.statusText}`);
14
8
  const text = await res.text();
15
- const all = (0, sync_1.parse)(text, {
9
+ const all = parse(text, {
16
10
  columns: true,
17
11
  skip_empty_lines: true,
18
12
  }).map((row) => ({