From 0af5e048b64fbb33ffa8276ecd888967e51a7e54 Mon Sep 17 00:00:00 2001 From: Aaryan Choudhary Date: Fri, 23 Oct 2026 10:05:39 +0530 Subject: [PATCH 1/4] chore(accessibility): deprecate the accessibilityExpert tool accessibilityExpert is going away. Until it is removed it keeps answering from BrowserStack's accessibility knowledge base, so nothing that calls it breaks. Its description and title now say it is deprecated, each answer starts with a note that it will be removed and what to use instead (answer general WCAG questions directly; use startAccessibilityScan or fetchAccessibilityIssues for a page's or a report's issues), and docs/TOOLS.md marks it. Co-Authored-By: Claude Opus 5.5 --- docs/TOOLS.md | 2 +- src/tools/accessibility.ts | 20 +++- .../accessibilityExpertDeprecated.test.ts | 99 +++++++++++++++++++ 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 tests/tools/accessibilityExpertDeprecated.test.ts diff --git a/docs/TOOLS.md b/docs/TOOLS.md index e8233c92..9ba84bcc 100644 --- a/docs/TOOLS.md +++ b/docs/TOOLS.md @@ -341,7 +341,7 @@ searchCapability → describeCapability → invokeCapability | Tool | What it does | |---|---| | `startAccessibilityScan` | Start a web accessibility scan of a page URL and retrieve a local CSV report path. Optional settings: `wcagVersion` (WCAG 2.0–2.2 at A/AA/AAA, or RGAA 4.1), `bestPractices`, `needsReview`, `advancedRules` and `experimentalRules`; the answer states the settings the scan ran with. Mobile apps are scanned through an App Automate run instead (`setupBrowserStackAppAutomateTests` with `accessibility: true`). | -| `accessibilityExpert` | Ask the A11y Expert (WCAG 2.0/2.1/2.2, mobile/web usability, best practices). | +| `accessibilityExpert` | **Deprecated, to be removed.** Ask the A11y Expert (WCAG 2.0/2.1/2.2, mobile/web usability, best practices). | | `createAccessibilityAuthConfig` | Create an authentication configuration (form-based or basic) for accessibility scans behind a login. | | `getAccessibilityAuthConfig` | Retrieve an existing accessibility authentication configuration by ID. | | `fetchAccessibilityIssues` | Fetch accessibility issues, with pagination, from a Website Scanner run, an Automated Tests build (web) or App Accessibility build (mobile app, by the build id the SDK prints), a Workflow Analyzer report, an App Accessibility manual report (`appReportId`), or a report's dashboard link. Once the tests or scan have finished, waits while the report is still processing; a run still in progress is read as it is, with a note. For an app build with no scans, lists the likely causes. | diff --git a/src/tools/accessibility.ts b/src/tools/accessibility.ts index 2936bc04..7a803b6d 100644 --- a/src/tools/accessibility.ts +++ b/src/tools/accessibility.ts @@ -148,6 +148,13 @@ async function initializeReportFetcher( return reportFetcher; } +/** + * accessibilityExpert is going away; until it is removed it still answers, with this note, + * which names what to use instead so an agent stops reaching for it. + */ +const ACCESSIBILITY_EXPERT_DEPRECATED = + "Note: accessibilityExpert is deprecated and will be removed in a future release. Answer general WCAG and accessibility questions directly; for the issues on a page or in a report, use startAccessibilityScan or fetchAccessibilityIssues."; + async function executeAccessibilityRAG( args: { query: string }, server: McpServer, @@ -160,7 +167,14 @@ async function executeAccessibilityRAG( undefined, config, ); - return await queryAccessibilityRAG(args.query, config); + const answer = await queryAccessibilityRAG(args.query, config); + return { + ...answer, + content: [ + { type: "text", text: ACCESSIBILITY_EXPERT_DEPRECATED }, + ...answer.content, + ], + }; } catch (error) { return handleMCPError("accessibilityExpert", server, config, error); } @@ -1584,7 +1598,7 @@ export default function addAccessibilityTools( tools.accessibilityExpert = server.tool( "accessibilityExpert", - "Answer accessibility, a11y, and WCAG questions using BrowserStack's accessibility knowledge base.", + "Deprecated, to be removed: answers accessibility, a11y, and WCAG questions from BrowserStack's accessibility knowledge base.", { query: z .string() @@ -1593,7 +1607,7 @@ export default function addAccessibilityTools( ), }, { - title: "Accessibility Expert", + title: "Accessibility Expert (deprecated)", readOnlyHint: true, openWorldHint: false, destructiveHint: false, diff --git a/tests/tools/accessibilityExpertDeprecated.test.ts b/tests/tools/accessibilityExpertDeprecated.test.ts new file mode 100644 index 00000000..2680c96f --- /dev/null +++ b/tests/tools/accessibilityExpertDeprecated.test.ts @@ -0,0 +1,99 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +// accessibilityExpert is deprecated: it still answers, so nothing that calls it breaks, but +// an agent choosing a tool, and anyone reading an answer, is told it is going away. + +const m = vi.hoisted(() => ({ queryAccessibilityRAG: vi.fn() })); + +vi.mock("../../src/tools/accessiblity-utils/accessibility-rag.js", () => ({ + queryAccessibilityRAG: m.queryAccessibilityRAG, +})); +vi.mock("../../src/lib/instrumentation.js", () => ({ trackMCP: vi.fn() })); +vi.mock("../../src/logger.js", () => ({ + default: { error: vi.fn(), info: vi.fn(), debug: vi.fn(), warn: vi.fn() }, +})); +vi.mock("../../src/index.js", () => ({ + trackMCP: vi.fn(), + PackageJsonVersion: "0.0.0", +})); + +import addAccessibilityTools from "../../src/tools/accessibility.js"; + +function register() { + const tools: Record< + string, + { prompt: string; annotations: any; handler: (...a: any[]) => any } + > = {}; + const server: any = { + tool: vi.fn((...args: any[]) => { + tools[args[0]] = { + prompt: args[1], + annotations: args[args.length - 2], + handler: args[args.length - 1], + }; + }), + server: { getClientVersion: vi.fn().mockReturnValue({ version: "1.0" }) }, + }; + addAccessibilityTools(server, { + "browserstack-username": "fake-user", + "browserstack-access-key": "fake-key", + } as any); + return tools; +} + +const text = (result: any) => + result.content.map((c: { text: string }) => c.text).join("\n"); + +describe("accessibilityExpert (deprecated)", () => { + beforeEach(() => { + vi.clearAllMocks(); + m.queryAccessibilityRAG.mockResolvedValue({ + content: [ + { + type: "text", + text: "Text needs a contrast ratio of at least 4.5:1.", + }, + ], + }); + }); + + it("says it is deprecated where an agent picks its tools", () => { + const expert = register().accessibilityExpert; + + expect(expert.prompt).toMatch(/^Deprecated/); + expect(expert.prompt).toMatch(/removed/); + expect(expert.annotations.title).toMatch(/deprecated/i); + }); + + it("still answers from the knowledge base, with a note that it is deprecated", async () => { + const result = await register().accessibilityExpert.handler({ + query: "What contrast does body text need?", + }); + + expect(m.queryAccessibilityRAG).toHaveBeenCalledWith( + "What contrast does body text need?", + expect.anything(), + ); + expect(result.isError).toBeFalsy(); + expect(text(result)).toContain( + "Text needs a contrast ratio of at least 4.5:1.", + ); + expect(result.content[0].text).toMatch( + /accessibilityExpert is deprecated and will be removed/, + ); + // A deprecation names what to use instead. + expect(result.content[0].text).toContain( + "use startAccessibilityScan or fetchAccessibilityIssues", + ); + }); + + it("still reports a failed lookup as an error", async () => { + m.queryAccessibilityRAG.mockRejectedValue( + new Error("RAG endpoint error: 503"), + ); + + const result = await register().accessibilityExpert.handler({ query: "q" }); + + expect(result.isError).toBe(true); + }); +}); From eaba944cfbdcfb567d1ef9074c083ed8f1857a64 Mon Sep 17 00:00:00 2001 From: Aaryan Choudhary <76112295+Aaryan430@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:02:43 +0530 Subject: [PATCH 2/4] Delete tests/tools/accessibilityExpertDeprecated.test.ts --- .../accessibilityExpertDeprecated.test.ts | 99 ------------------- 1 file changed, 99 deletions(-) delete mode 100644 tests/tools/accessibilityExpertDeprecated.test.ts diff --git a/tests/tools/accessibilityExpertDeprecated.test.ts b/tests/tools/accessibilityExpertDeprecated.test.ts deleted file mode 100644 index 2680c96f..00000000 --- a/tests/tools/accessibilityExpertDeprecated.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; - -// accessibilityExpert is deprecated: it still answers, so nothing that calls it breaks, but -// an agent choosing a tool, and anyone reading an answer, is told it is going away. - -const m = vi.hoisted(() => ({ queryAccessibilityRAG: vi.fn() })); - -vi.mock("../../src/tools/accessiblity-utils/accessibility-rag.js", () => ({ - queryAccessibilityRAG: m.queryAccessibilityRAG, -})); -vi.mock("../../src/lib/instrumentation.js", () => ({ trackMCP: vi.fn() })); -vi.mock("../../src/logger.js", () => ({ - default: { error: vi.fn(), info: vi.fn(), debug: vi.fn(), warn: vi.fn() }, -})); -vi.mock("../../src/index.js", () => ({ - trackMCP: vi.fn(), - PackageJsonVersion: "0.0.0", -})); - -import addAccessibilityTools from "../../src/tools/accessibility.js"; - -function register() { - const tools: Record< - string, - { prompt: string; annotations: any; handler: (...a: any[]) => any } - > = {}; - const server: any = { - tool: vi.fn((...args: any[]) => { - tools[args[0]] = { - prompt: args[1], - annotations: args[args.length - 2], - handler: args[args.length - 1], - }; - }), - server: { getClientVersion: vi.fn().mockReturnValue({ version: "1.0" }) }, - }; - addAccessibilityTools(server, { - "browserstack-username": "fake-user", - "browserstack-access-key": "fake-key", - } as any); - return tools; -} - -const text = (result: any) => - result.content.map((c: { text: string }) => c.text).join("\n"); - -describe("accessibilityExpert (deprecated)", () => { - beforeEach(() => { - vi.clearAllMocks(); - m.queryAccessibilityRAG.mockResolvedValue({ - content: [ - { - type: "text", - text: "Text needs a contrast ratio of at least 4.5:1.", - }, - ], - }); - }); - - it("says it is deprecated where an agent picks its tools", () => { - const expert = register().accessibilityExpert; - - expect(expert.prompt).toMatch(/^Deprecated/); - expect(expert.prompt).toMatch(/removed/); - expect(expert.annotations.title).toMatch(/deprecated/i); - }); - - it("still answers from the knowledge base, with a note that it is deprecated", async () => { - const result = await register().accessibilityExpert.handler({ - query: "What contrast does body text need?", - }); - - expect(m.queryAccessibilityRAG).toHaveBeenCalledWith( - "What contrast does body text need?", - expect.anything(), - ); - expect(result.isError).toBeFalsy(); - expect(text(result)).toContain( - "Text needs a contrast ratio of at least 4.5:1.", - ); - expect(result.content[0].text).toMatch( - /accessibilityExpert is deprecated and will be removed/, - ); - // A deprecation names what to use instead. - expect(result.content[0].text).toContain( - "use startAccessibilityScan or fetchAccessibilityIssues", - ); - }); - - it("still reports a failed lookup as an error", async () => { - m.queryAccessibilityRAG.mockRejectedValue( - new Error("RAG endpoint error: 503"), - ); - - const result = await register().accessibilityExpert.handler({ query: "q" }); - - expect(result.isError).toBe(true); - }); -}); From 678d3cde66432d3debbd45f373e5fafad6676ad0 Mon Sep 17 00:00:00 2001 From: Aaryan Choudhary Date: Wed, 11 Nov 2026 14:48:09 +0530 Subject: [PATCH 3/4] fix(accessibility): point accessibilityExpert's deprecation note to askBrowserStackAI for advice Listing or filtering a report's issues goes to fetchAccessibilityIssues; advice on a report, such as raising its score or what to fix first, goes to askBrowserStackAI. Co-Authored-By: Claude Opus 5.5 --- src/tools/accessibility.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/accessibility.ts b/src/tools/accessibility.ts index 7a803b6d..15ad6e3e 100644 --- a/src/tools/accessibility.ts +++ b/src/tools/accessibility.ts @@ -153,7 +153,7 @@ async function initializeReportFetcher( * which names what to use instead so an agent stops reaching for it. */ const ACCESSIBILITY_EXPERT_DEPRECATED = - "Note: accessibilityExpert is deprecated and will be removed in a future release. Answer general WCAG and accessibility questions directly; for the issues on a page or in a report, use startAccessibilityScan or fetchAccessibilityIssues."; + "Note: accessibilityExpert is deprecated and will be removed in a future release. To list or filter a report's issues, for example those failing a WCAG criterion, use fetchAccessibilityIssues and answer from its result; to scan a page, use startAccessibilityScan. For advice on a report, such as how to raise its score or which issues to fix first, call askBrowserStackAI with product a11y and give the user its answer. If askBrowserStackAI says it is not enabled for this account, answer from the report's issues."; async function executeAccessibilityRAG( args: { query: string }, From e11a0c38329eda798c3ce335ccf3e83cf4e5502d Mon Sep 17 00:00:00 2001 From: Aaryan Choudhary Date: Thu, 12 Nov 2026 14:03:08 +0530 Subject: [PATCH 4/4] fix(accessibility): point general WCAG questions at askBrowserStackAI in the deprecation note accessibilityExpert's deprecation note named replacements for report questions only. It now sends general WCAG or ARIA questions to askBrowserStackAI with product a11y too, matching the fix prompt. Co-Authored-By: Claude Opus 5.5 --- src/tools/accessibility.ts | 2 +- tests/tools/accessibilityExpertQuery.test.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/accessibility.ts b/src/tools/accessibility.ts index e2d95611..0bd9141f 100644 --- a/src/tools/accessibility.ts +++ b/src/tools/accessibility.ts @@ -163,7 +163,7 @@ async function initializeReportFetcher( * which names what to use instead so an agent stops reaching for it. */ const ACCESSIBILITY_EXPERT_DEPRECATED = - "Note: accessibilityExpert is deprecated and will be removed in a future release. To list or filter a report's issues, for example those failing a WCAG criterion, use fetchAccessibilityIssues and answer from its result; to scan a page, use startAccessibilityScan. For advice on a report, such as how to raise its score or which issues to fix first, call askBrowserStackAI with product a11y and give the user its answer. If askBrowserStackAI says it is not enabled for this account, answer from the report's issues."; + "Note: accessibilityExpert is deprecated and will be removed in a future release. To list or filter a report's issues, for example those failing a WCAG criterion, use fetchAccessibilityIssues and answer from its result; to scan a page, use startAccessibilityScan. For advice on a report, such as how to raise its score or which issues to fix first, call askBrowserStackAI with product a11y and give the user its answer. For a general WCAG or ARIA question, call askBrowserStackAI with product a11y too. If askBrowserStackAI says it is not enabled for this account, answer from the report's issues."; async function executeAccessibilityRAG( args: { query: string }, diff --git a/tests/tools/accessibilityExpertQuery.test.ts b/tests/tools/accessibilityExpertQuery.test.ts index 9397a997..bb51fa9e 100644 --- a/tests/tools/accessibilityExpertQuery.test.ts +++ b/tests/tools/accessibilityExpertQuery.test.ts @@ -113,6 +113,9 @@ describe("accessibilityExpert with a long question", () => { expect(rag.query.mock.calls[0][0]).toBe(QUESTION); expect(result.content).toHaveLength(2); expect(result.content[0].text).toMatch(/^Note: accessibilityExpert is deprecated/); + expect(result.content[0].text).toContain( + "For a general WCAG or ARIA question, call askBrowserStackAI with product a11y too.", + ); expect(result.content[1]).toEqual({ type: "text", text: "Answer." }); }); });