Skip to content

Fix local urls support in a11y scan #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 22, 2025
Merged
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@browserstack/mcp-server",
"version": "1.1.3",
"version": "1.1.4",
"description": "BrowserStack's Official MCP Server",
"main": "dist/index.js",
"repository": {
Expand Down
39 changes: 19 additions & 20 deletions src/lib/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export async function killExistingBrowserStackLocalProcesses() {
}
}

export async function ensureLocalBinarySetup(localIdentifier?: string): Promise<void> {
export async function ensureLocalBinarySetup(
localIdentifier?: string,
): Promise<void> {
logger.info(
"Ensuring local binary setup as it is required for private URLs...",
);
Expand All @@ -87,33 +89,30 @@ export async function ensureLocalBinarySetup(localIdentifier?: string): Promise<
localIdentifier?: string;
} = {
key: config.browserstackAccessKey,
username: config.browserstackUsername
username: config.browserstackUsername,
};

if (localIdentifier) {
requestBody.localIdentifier = localIdentifier;
}

return await new Promise((resolve, reject) => {
localBinary.start(
requestBody,
(error?: Error) => {
if (error) {
logger.error(
`Unable to start BrowserStack Local... please check your credentials and try again. Error: ${error}`,
);
localBinary.start(requestBody, (error?: Error) => {
if (error) {
logger.error(
`Unable to start BrowserStack Local... please check your credentials and try again. Error: ${error}`,
);

reject(
new Error(
`Unable to configure local tunnel binary, please check your credentials and try again. Error: ${error}`,
),
);
} else {
logger.info("Successfully started BrowserStack Local");
resolve();
}
},
);
reject(
new Error(
`Unable to configure local tunnel binary, please check your credentials and try again. Error: ${error}`,
),
);
} else {
logger.info("Successfully started BrowserStack Local");
resolve();
}
});
});
}

Expand Down
9 changes: 4 additions & 5 deletions src/tools/accessiblity-utils/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ export class AccessibilityScanner {
name: string,
urlList: string[],
): Promise<AccessibilityScanResponse> {

// Check if any URL is local
const hasLocal = urlList.some(isLocalURL);
const localIdentifier = crypto.randomUUID();
const LOCAL_IP = "127.0.0.1";
const localHosts = new Set(["127.0.0.1", "localhost", "0.0.0.0"]);
const BS_LOCAL_DOMAIN = "bs-local.com";

if (hasLocal) {
Expand All @@ -45,13 +44,13 @@ export class AccessibilityScanner {
const transformedUrlList = urlList.map((url) => {
try {
const parsed = new URL(url);
if (parsed.hostname === LOCAL_IP) {
if (localHosts.has(parsed.hostname)) {
parsed.hostname = BS_LOCAL_DOMAIN;
return parsed.toString();
}
return url;
} catch (e) {
logger.warn(`[AccessibilityScan] Invalid URL skipped: ${url}`);
logger.warn(`[AccessibilityScan] Invalid URL skipped: ${e}`);
return url;
}
});
Expand All @@ -68,7 +67,7 @@ export class AccessibilityScanner {
localTestingInfo: {
localIdentifier,
localEnabled: true,
}
},
};
requestBody = { ...baseRequestBody, ...localConfig };
}
Expand Down