Skip to main content
Glama
yashpreetbathla

MCP Accessibility Bridge

README.md
<div align="center">

# MCP Accessibility Bridge

**Expose any live webpage's accessibility tree to Claude — generate rock-solid, framework-agnostic test selectors in seconds.**

[![npm version](https://img.shields.io/npm/v/mcp-accessibility-bridge.svg?color=red)](https://www.npmjs.com/package/mcp-accessibility-bridge)
[![npm downloads](https://img.shields.io/npm/dm/mcp-accessibility-bridge.svg?color=blue)](https://www.npmjs.com/package/mcp-accessibility-bridge)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Node.js](https://img.shields.io/badge/Node.js-18%2B-green.svg)](https://nodejs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue.svg)](https://www.typescriptlang.org)
[![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.10-purple.svg)](https://github.com/modelcontextprotocol/sdk)

<br/>

![Architecture](screenshots/01-architecture.svg)

</div>

---

## Quick Start

No cloning. No building. Paste this into your Claude Desktop config and you're done:

```json
{
  "mcpServers": {
    "accessibility-bridge": {
      "command": "npx",
      "args": ["-y", "mcp-accessibility-bridge"]
    }
  }
}
```

---

## What Is This?

MCP Accessibility Bridge is a **stdio MCP server** that connects Claude Desktop to a live Chrome browser via the [Chrome DevTools Protocol (CDP)](https://chromedevtools.github.io/devtools-protocol/). It exposes the browser's full ARIA accessibility tree so Claude can:

- Read every element's role, name, state, and relationships exactly as a screen reader would
- Generate reliable, stable test selectors for **Playwright, Selenium, Cypress, and WebdriverIO** — without ever opening DevTools
- Audit pages for accessibility issues
- Write, debug, and migrate test suites using natural language

> **No bundled Chromium.** Uses your existing Chrome installation via `puppeteer-core`.

---

## Table of Contents

- [Quick Start](#quick-start)
- [Architecture](#architecture)
- [Why the Accessibility Tree?](#why-the-accessibility-tree)
- [8 MCP Tools](#8-mcp-tools)
- [Selector Priority Engine](#selector-priority-engine)
- [Real-World Use Cases](#real-world-use-cases)
- [Chrome Setup](#chrome-setup)
- [Claude Desktop Configuration](#claude-desktop-configuration)
- [Usage Examples](#usage-examples)
- [Example Project](#example-project)
- [Project Structure](#project-structure)
- [How It Works (Deep Dive)](#how-it-works-deep-dive)
- [Contributing](#contributing)
- [License](#license)

---

## Architecture

```
┌─────────────────────────────────────────────────────────────────────┐
│                        Claude Desktop                               │
│                                                                     │
│   ┌─────────────┐    MCP (stdio)    ┌──────────────────────────┐   │
│   │   Claude    │◄─────────────────►│  MCP Accessibility       │   │
│   │   LLM       │   JSON-RPC 2.0    │  Bridge (Node.js)        │   │
│   └─────────────┘                   │                          │   │
│                                     │  ┌────────────────────┐  │   │
│                                     │  │  8 MCP Tools       │  │   │
│                                     │  │  browser_connect   │  │   │
│                                     │  │  browser_navigate  │  │   │
│                                     │  │  get_ax_tree       │  │   │
│                                     │  │  query_ax_tree     │  │   │
│                                     │  │  get_element_props │  │   │
│                                     │  │  get_interactive   │  │   │
│                                     │  │  get_focused       │  │   │
│                                     │  │  browser_disconnect│  │   │
│                                     │  └────────┬───────────┘  │   │
│                                     │           │               │   │
│                                     │  ┌────────▼───────────┐  │   │
│                                     │  │  BrowserManager    │  │   │
│                                     │  │  (Singleton)       │  │   │
│                                     │  │  Browser + Page +  │  │   │
│                                     │  │  CDPSession        │  │   │
│                                     │  └────────┬───────────┘  │   │
│                                     │           │               │   │
│                                     │  ┌────────▼───────────┐  │   │
│                                     │  │  Utilities         │  │   │
│                                     │  │  axTree.ts         │  │   │
│                                     │  │  selectorGen.ts    │  │   │
│                                     │  │  errors.ts         │  │   │
│                                     │  └────────────────────┘  │   │
│                                     └────────────┬─────────────┘   │
└──────────────────────────────────────────────────┼─────────────────┘
                                                   │
                                     CDP WebSocket │
                                     (port 9222)   │
                                                   │
                              ┌────────────────────▼──────────────────┐
                              │          Google Chrome                 │
                              │                                        │
                              │  ┌──────────────────────────────────┐  │
                              │  │  Active Tab                      │  │
                              │  │                                  │  │
                              │  │  DOM Tree ──► AX Tree            │  │
                              │  │                ▲                 │  │
                              │  │  Computed      │                 │  │
                              │  │  Accessibility │                 │  │
                              │  │  Object Model  │                 │  │
                              │  └────────────────┼─────────────────┘  │
                              │                   │                    │
                              │   CDP Domains Used:                    │
                              │   • Accessibility.enable               │
                              │   • Accessibility.getFullAXTree        │
                              │   • Accessibility.getPartialAXTree     │
                              │   • Accessibility.queryAXTree          │
                              │   • DOM.describeNode                   │
                              │   • DOM.getOuterHTML                   │
                              └────────────────────────────────────────┘
```

### Data Flow

```
User prompt in Claude Desktop
         │
         ▼
Claude decides which tool to call
         │
         ▼
MCP SDK dispatches tool call (stdio JSON-RPC)
         │
         ▼
Tool handler in src/tools/
         │
         ▼
BrowserManager.requireConnection()
     returns { browser, page, cdpSession }
         │
         ▼
CDP commands sent over WebSocket to Chrome
         │
         ▼
Chrome computes AX tree from live DOM
         │
         ▼
Raw CDP response parsed + transformed
         │
         ▼
selectorGenerator.ts builds multi-framework selectors
         │
         ▼
toolSuccess({ ... }) → JSON returned to Claude
         │
         ▼
Claude reads selectors, names, roles → responds to user
```

---

## Why the Accessibility Tree?

Most test automation targets the **DOM** — brittle class names, nested div soup, hashed CSS modules. The accessibility tree is different:

| Property | DOM Selectors | AX Tree Selectors |
|---|---|---|
| **Stability** | Break on CSS refactors | Stable across visual redesigns |
| **Dynamic state** | Miss `disabled`, `expanded`, `checked` | Reflect real runtime state |
| **Semantic meaning** | Target implementation details | Target user-facing intent |
| **Framework coupling** | Often framework-specific | Framework-agnostic |
| **Accessibility signal** | Silent on a11y problems | Surface a11y bugs automatically |
| **Screen reader parity** | Unknown | Exactly what a screen reader announces |

The AX tree is Chrome's **computed semantic model** — what the browser exposes to assistive technology. Selectors built from it use `role` and `name` attributes that are:

1. **Immune to visual redesigns** — renaming a CSS class doesn't change `role=button[name='Submit']`
2. **Semantically verified** — if Claude can select it, a screen reader can reach it
3. **Framework-neutral** — the same ARIA semantics translate to any test framework

---

## 8 MCP Tools

### `browser_connect`

Connect Claude to a running Chrome instance via CDP.

```
Input:  debugUrl (string, default: "http://localhost:9222")
Output: { connected, debugUrl, currentUrl, pageTitle }
```

Chrome must be started with `--remote-debugging-port=9222`. The tool creates a single shared `CDPSession` that all other tools reuse, enabling `Accessibility.*` CDP domain calls.

---

### `browser_navigate`

Navigate the connected tab to any URL.

```
Input:  url (string), waitUntil (load|domcontentloaded|networkidle0|networkidle2), timeout (ms)
Output: { navigated, url, finalUrl, title, status }
```

Returns the HTTP status code and final URL (after redirects).

---

### `browser_disconnect`

Close the CDP connection cleanly. Does **not** kill Chrome.

```
Input:  (none)
Output: { disconnected, message }
```

---

### `get_accessibility_tree`

Snapshot the full accessibility tree of the current page.

```
Input:  interestingOnly (bool), maxDepth (int), useFullTree (bool)
Output: { url, title, nodeCount, tree }
```

Two modes:
- **Default:** `page.accessibility.snapshot()` — fast, filters noise, ideal for most pages
- **Full CDP:** `Accessibility.getFullAXTree` — raw, complete, slower — use when the default misses nodes

---

### `query_accessibility_tree`

Search the tree by ARIA role and/or accessible name.

```
Input:  role (string), accessibleName (string), backendNodeId (int)
Output: { query, count, nodes[] }
```

Uses CDP `Accessibility.queryAXTree` — targeted and fast. Example: find all unchecked checkboxes, all level-2 headings, all disabled buttons.

---

### `get_element_properties`

Given a CSS selector, return the element's full AX profile and multi-framework selectors.

```
Input:  selector (string), includeHtml (bool)
Output: { selector, tagName, domAttributes, backendNodeId, accessibility, suggestedSelectors }
```

Resolves: `CSS selector → backendNodeId → Accessibility.getPartialAXTree → selectorGenerator`.

---

### `get_interactive_elements`

Find every interactive element on the page — buttons, inputs, links, tabs, etc.

```
Input:  roles (string[]), includeDisabled (bool), maxElements (int)
Output: { totalFound, returned, elements[] }
```

Filters `Accessibility.getFullAXTree` by **20 interactive ARIA roles**, then calls `DOM.describeNode` in parallel for each to retrieve DOM attributes for selector generation.

**20 covered roles:**
`button` · `link` · `textbox` · `searchbox` · `combobox` · `listbox` · `option` · `checkbox` · `radio` · `switch` · `slider` · `spinbutton` · `menuitem` · `tab` · `treeitem` · `gridcell` · `rowheader` · `columnheader` · `progressbar` · `scrollbar`

---

### `get_focused_element`

Return the currently keyboard-focused element's AX info and selectors.

```
Input:  (none)
Output: { focused: { role, name, value, tagName, domAttributes, suggestedSelectors } }
```

Uses `document.activeElement` + `Accessibility.getPartialAXTree` to report what a keyboard user is currently on.

---

## Selector Priority Engine

![Selector Priority Engine](screenshots/02-selector-priority.svg)

`src/utils/selectorGenerator.ts` implements a 4-tier priority system:

```
Priority 1 — Test ID attributes (HIGHEST STABILITY)
──────────────────────────────────────────────────
Checks: data-testid, data-cy, data-test, data-qa
Output: [data-testid="submit-btn"]
Playwright: page.getByTestId('submit-btn')


Priority 2 — Stable element ID
──────────────────────────────────────────────────
Checks: id attribute
Skips:  UUIDs, numeric IDs, mat-* / ng-* prefixes
Output: #email-input
Playwright: page.locator('#email-input')


Priority 3 — ARIA role + accessible name (MEDIUM STABILITY)
──────────────────────────────────────────────────
Uses: role + computed accessible name from AX tree
Output: role=button[name='Submit']
Playwright: page.getByRole('button', { name: 'Submit' })


Priority 4 — Semantic CSS (FALLBACK)
──────────────────────────────────────────────────
Uses: tagName + type/name/role/placeholder attributes
Output: input[type="email"][name="email"]
Playwright: page.locator('input[type="email"][name="email"]')
```

Every element returns selectors for all four frameworks:

```json
{
  "testId": "[data-testid=\"search-input\"]",
  "aria": "role=searchbox[name='Search']",
  "css": "input[type=\"search\"]",
  "playwright": "page.getByRole('searchbox', { name: 'Search' })",
  "selenium": "driver.find_element(By.CSS_SELECTOR, '[data-testid=\"search-input\"]')",
  "cypress": "cy.get('[data-testid=\"search-input\"]')",
  "webdriverio": "$('[data-testid=\"search-input\"]')",
  "stability": "high",
  "recommended": "page.getByTestId('search-input')"
}
```

---

## Real-World Use Cases

![Workflow](screenshots/04-workflow.svg)

### 1. Instant Test Suite from Zero

A legacy app with no tests. Navigate to any page and ask:
> *"Generate a Playwright test that fills the checkout form and submits it."*

Claude calls `get_interactive_elements`, receives all inputs and buttons with selectors, and writes the full test — in minutes, not days.

### 2. Cross-Framework Selector Migration

Moving from Selenium to Playwright? Hundreds of brittle XPath selectors?
> *"Give me the Playwright equivalent of every interactive element on this page."*

Claude maps `driver.find_element(By.XPATH, ...)` → `page.getByRole(...)` using the live AX tree as ground truth.

### 3. Accessibility Audit

> *"Get the full accessibility tree for /checkout and identify elements missing accessible names, wrong roles, or bad focus order."*

Claude reads the AX tree and reports:
- Buttons with `name: ""` (icon buttons missing `aria-label`)
- `<div>` acting as buttons (`role: generic`, no keyboard access)
- Form fields missing `required` or `aria-describedby`

### 4. Debugging Flaky Tests

> *"The test can't find #submit-btn. Navigate to the page and check if it exists in the AX tree, and if it's enabled."*

Claude checks: is the element ignored? Is `disabled: true`? Is a modal trapping focus? All invisible to raw DOM queries, visible here.

### 5. Component Library Selector Documentation

> *"Open Storybook at localhost:6006 and document the recommended selector for every interactive element in every story."*

Claude iterates stories, calls `get_interactive_elements`, and outputs a complete selector reference.

### 6. Natural Language → Selector (for Non-Technical QA)

> *"Find the selector for the blue submit button at the bottom of the registration form."*

No DevTools needed. Claude queries the AX tree, identifies the button by its accessible name, and returns all four framework selectors.

### 7. Dynamic SPA Testing

React/Vue/Angular apps with hashed class names (`sc-abc123`) break CSS selectors on every build. AX tree selectors (`page.getByRole('button', { name: 'Subscribe' })`) are permanently stable — hashing class names never changes semantic meaning.

### 8. Pre-Merge Selector Validation

> *"Before merging this PR, verify these 10 selectors still resolve correctly on staging."*

Claude calls `get_element_properties` for each selector and confirms role + name still match expected values. Catches regressions before CI runs.

---

## Chrome Setup

Chrome must be running with the remote debugging port open **before** calling `browser_connect`.

### macOS

```bash
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/chrome-debug-profile
```

### Linux

```bash
google-chrome \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/chrome-debug-profile
```

### Windows (PowerShell)

```powershell
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
  --remote-debugging-port=9222 `
  --user-data-dir="$env:TEMP\chrome-debug-profile"
```

### Verify Chrome is Ready

```bash
curl http://localhost:9222/json/version
```

Expected response:
```json
{
  "Browser": "Chrome/124.0.0.0",
  "Protocol-Version": "1.3",
  "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/..."
}
```

> **Why a separate `--user-data-dir`?** Chrome requires a dedicated profile directory when remote debugging is enabled. Using `/tmp/chrome-debug-profile` keeps it isolated from your regular browsing profile.

---

## Claude Desktop Configuration

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows).

### Option 1 — npx (recommended)

Zero install. Works on any machine. `npx` downloads the package on first run and caches it.

```json
{
  "mcpServers": {
    "accessibility-bridge": {
      "command": "npx",
      "args": ["-y", "mcp-accessibility-bridge"]
    }
  }
}
```

### Option 2 — Global install

```bash
npm install -g mcp-accessibility-bridge
```

Then use just the command name — no path, no args:

```json
{
  "mcpServers": {
    "accessibility-bridge": {
      "command": "mcp-accessibility-bridge"
    }
  }
}
```

### Option 3 — Local dev (cloned repo)

```bash
git clone https://github.com/yashpreetbathla/mcp-accessibility-bridge.git
cd mcp-accessibility-bridge
npm install && npm run build
npm link
```

Config becomes identical to Option 2. Any local edits are reflected immediately without reinstalling.

**After saving:** fully quit Claude Desktop (`Cmd+Q` on macOS), then relaunch. The `accessibility-bridge` tools will appear in Claude's tool list.

---

## Usage Examples

### Connect and Navigate

> *"Connect to Chrome and navigate to https://github.com"*

Claude calls `browser_connect` then `browser_navigate` and confirms the page title and HTTP status.

### Get the Accessibility Tree

![Tool Output Example](screenshots/03-tool-output.svg)

> *"Show me the accessibility tree for this page, 5 levels deep"*

```json
{
  "url": "https://github.com",
  "title": "GitHub",
  "nodeCount": 847,
  "tree": {
    "role": "WebArea",
    "name": "GitHub",
    "children": [
      { "role": "banner", "name": "", "children": ["..."] },
      { "role": "main",   "name": "", "children": ["..."] }
    ]
  }
}
```

### Find All Buttons

> *"List all buttons on this page with their Playwright selectors"*

```json
{
  "totalFound": 12,
  "elements": [
    {
      "role": "button",
      "name": "Sign in",
      "suggestedSelectors": {
        "playwright":  "page.getByRole('button', { name: 'Sign in' })",
        "selenium":    "driver.find_element(By.XPATH, \"//button[@aria-label='Sign in']\")",
        "cypress":     "cy.get('[data-testid=\"sign-in-btn\"]')",
        "webdriverio": "$('[data-testid=\"sign-in-btn\"]')",
        "stability":   "high",
        "recommended": "page.getByRole('button', { name: 'Sign in' })"
      }
    }
  ]
}
```

### Inspect a Specific Element

> *"What's the best selector for the search input on this page?"*

Claude calls `get_element_properties` with `selector: "input[type=search]"` and returns the full AX profile + all framework selectors.

### Check What's Focused

> *"What element is currently focused on the keyboard?"*

Claude calls `get_focused_element` and returns the role, name, and selectors of the active element — useful for testing keyboard navigation and focus management.

---

## Example Project

The [`examples/playwright-github-tests/`](examples/playwright-github-tests/) directory contains a complete Playwright test suite for GitHub built entirely using selectors generated by Claude + this MCP server. Zero time was spent in Chrome DevTools.

```
examples/playwright-github-tests/
├── selectors/
│   └── github.selectors.ts        ← selector library generated by Claude
└── tests/
    ├── github-home.spec.ts         ← home page landmark + CTA tests
    ├── github-login.spec.ts        ← login form: happy path, tab order, error alerts
    ├── github-search.spec.ts       ← search flow + keyboard shortcut discovery
    └── accessibility-audit.spec.ts ← WCAG 2.1 AA: headings, labels, focus trapping
```

Every selector has a comment showing which Claude prompt and which MCP tool produced it. See the [example README](examples/playwright-github-tests/README.md) for the full walkthrough.

---

## Project Structure

```
mcp-accessibility-bridge/
├── package.json                   # ESM module, bin entry, npm metadata
├── tsconfig.json                  # ES2022, NodeNext modules
├── bin/
│   └── mcp-accessibility-bridge.js  # CLI entry point (shebang wrapper)
├── src/
│   ├── index.ts                   # McpServer setup, tool registration, stdio transport
│   ├── browser/
│   │   ├── BrowserManager.ts      # Singleton: Browser + Page + CDPSession lifecycle
│   │   └── types.ts               # CDP response interfaces (CdpAXNode, etc.)
│   ├── tools/
│   │   ├── browserConnect.ts      # browser_connect
│   │   ├── browserNavigate.ts     # browser_navigate
│   │   ├── browserDisconnect.ts   # browser_disconnect
│   │   ├── getAccessibilityTree.ts    # get_accessibility_tree
│   │   ├── queryAccessibilityTree.ts  # query_accessibility_tree
│   │   ├── getElementProperties.ts    # get_element_properties
│   │   ├── getInteractiveElements.ts  # get_interactive_elements
│   │   └── getFocusedElement.ts       # get_focused_element
│   └── utils/
│       ├── axTree.ts              # Tree assembly, traversal, pruning
│       ├── selectorGenerator.ts   # 4-priority selector engine
│       └── errors.ts              # toolSuccess(), toolError(), BrowserNotConnectedError
├── examples/
│   └── playwright-github-tests/   # Full Playwright suite generated with this tool
├── screenshots/                   # Architecture + workflow diagrams
├── README.md
├── POLICY.md                      # Responsible use guidelines
└── LICENSE
```

### Key Design Decisions

**Singleton BrowserManager** — One `CDPSession` is created at `browser_connect` time and reused across all tool calls. This avoids the overhead of creating a new session per call and ensures `Accessibility.enable` is called exactly once.

**`puppeteer-core` only** — No bundled Chromium download (~300MB). Connects to the user's existing Chrome via `browserURL`. This is intentional: you want to inspect the same browser you use day-to-day.

**`browser.disconnect()` not `browser.close()`** — The MCP server does not own the Chrome process. `disconnect()` closes the WebSocket connection without killing Chrome.

**Parallel DOM resolution** — `get_interactive_elements` calls `DOM.describeNode` for all matched AX nodes via `Promise.all`. For pages with 50+ interactive elements, this is 5–10x faster than sequential calls.

**Never throw through MCP** — All tool handlers wrap execution in `try/catch` and return `toolError()` on failure. MCP errors are surfaced as readable text, not unhandled exceptions.

---

## How It Works (Deep Dive)

### CDP Accessibility Domain

Chrome DevTools Protocol exposes the `Accessibility` domain, which provides programmatic access to the browser's internal Accessibility Object Model (AOM). Before any AX calls can be made, the domain must be activated:

```typescript
await cdpSession.send('Accessibility.enable');
```

This is done once at connection time by `BrowserManager.connect()`.

### AX Node Resolution Pipeline

For `get_element_properties`:

```
page.$(cssSelector)                      // Puppeteer: find element
  → remoteObject.objectId                // V8 object reference
  → DOM.describeNode({ objectId })       // CDP: get backendNodeId + attributes
  → Accessibility.getPartialAXTree       // CDP: get AX nodes for this DOM node
    ({ backendNodeId, fetchRelatives: false })
  → cdpAXNodeToSummary()                 // Parse role, name, properties
  → buildSelectorFromRawNode()           // Generate selectors
```

### AX Tree Assembly

`Accessibility.getFullAXTree` returns a **flat array** of `CdpAXNode` objects with `nodeId`, `parentId`, and `childIds` references. The `axTree.ts` utilities:

1. **`buildTreeIndex`** — builds a `Map<nodeId, CdpAXNode>` for O(1) lookup
2. **`assembleTree`** — recursively walks `childIds`, skipping `ignored` nodes, building a nested `AXNodeSummary` tree
3. **`pruneToDepth`** — trims the tree to the requested `maxDepth`

### Selector Stability Heuristics

The `UNSTABLE_ID_RE` regex in `selectorGenerator.ts` skips IDs that are likely auto-generated:

```typescript
const UNSTABLE_ID_RE = /^(mat-|ng-|[0-9]|[a-f0-9]{8}-)/i;
```

This prevents Claude from recommending `#mat-input-3` (Angular Material auto-ID) or `#a3f2b1c4-...` (UUID) as stable selectors, falling back to ARIA role selectors instead.

---

## Contributing

Contributions are welcome. Please read [POLICY.md](POLICY.md) before contributing.

```bash
# Clone and set up
git clone https://github.com/yashpreetbathla/mcp-accessibility-bridge.git
cd mcp-accessibility-bridge
npm install

# Development mode (watch + recompile on save)
npm run dev

# One-off build
npm run build

# Link globally for local testing
npm link
```

**Areas to contribute:**
- Additional CDP domain support (e.g., `Page`, `Runtime` for JS state)
- Firefox DevTools Protocol support
- Shadow DOM / web component traversal
- Selector quality scoring improvements
- Unit tests for `selectorGenerator.ts` and `axTree.ts`

---

## License

MIT — see [LICENSE](LICENSE).

---

<div align="center">

**[npm](https://www.npmjs.com/package/mcp-accessibility-bridge) · [GitHub](https://github.com/yashpreetbathla/mcp-accessibility-bridge) · [Issues](https://github.com/yashpreetbathla/mcp-accessibility-bridge/issues) · [Author](https://yashpreetbathla.github.io/notion-flow-portfolio/)**

<br/>

Built to make test automation accessible to everyone — not just those fluent in CSS selectors and XPath.

</div>

TDQS

A4.1/5.0

Scored across 8 tools

Disambiguation5/5

Each tool has a clearly distinct purpose with no overlap: browser connection management, navigation, accessibility tree capture, element property retrieval, focus detection, interactive element listing, and tree querying. The descriptions clearly differentiate their functions, preventing misselection.

Naming Consistency5/5

All tools follow a consistent verb_noun or verb_adjective_noun pattern using snake_case (e.g., browser_connect, get_accessibility_tree, query_accessibility_tree). The naming is predictable and readable throughout the set.

Tool Count5/5

With 8 tools, the server is well-scoped for its accessibility testing domain. Each tool earns its place by covering essential operations like connection, navigation, tree analysis, and element inspection without being overly sparse or bloated.

Completeness5/5

The toolset provides complete coverage for accessibility testing workflows: browser setup, navigation, tree capture, element inspection, focus management, interactive element listing, and search capabilities. There are no obvious gaps, enabling agents to perform comprehensive accessibility analysis.

Maintenance

ActivityInactive
ResponsivenessNo issues