Skip to main content
Glama
PashaBoiko

Playwright Accessibility Testing MCP Server

by PashaBoiko

Playwright Accessibility Testing MCP Server

A production-ready Model Context Protocol (MCP) server for comprehensive accessibility testing using Playwright and axe-core. Test web applications for WCAG 2.0/2.1 compliance with ease.

Features

  • Comprehensive WCAG Testing: Tests WCAG 2.0/2.1 Level A/AA compliance plus best practices

  • Natural Language Testing: Find elements by visible text - no CSS selectors needed

  • Auto-Discovery: Automatically discover and test all interactive elements

  • Interactive Component Testing: Test across different states (dropdowns, modals, etc.)

  • Screenshot Capture: Visual documentation of tested areas

  • Predefined Prompts: Quick-start templates for common testing scenarios

  • Production-Ready: Modular architecture, TypeScript, comprehensive error handling

Related MCP server: Accessibility MCP Server

Installation

npm install
npm run build

Configuration

Add to your MCP client configuration file:

Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "playwright-a11y": {
      "command": "node",
      "args": ["/absolute/path/to/playwright-axe-mcp/dist/server.js"]
    }
  }
}

Claude Code (.claude/config.json in your project):

{
  "mcpServers": {
    "playwright-a11y": {
      "command": "node",
      "args": ["/absolute/path/to/playwright-axe-mcp/dist/server.js"]
    }
  }
}

Restart your MCP client after configuration.

Quick Start

Using the Predefined Prompt (Easiest!)

The fastest way to test is with the comprehensive-a11y-test prompt:

Use comprehensive-a11y-test prompt:
- url: https://example.com
- block: Rewards account
- steps: open menu, select provider, input value, click apply

Parameters:

  • url (required): URL to test

  • block (optional): Section name (e.g., "Navigation", "User Profile")

  • steps (optional): Comma-separated interaction steps

What it does:

  1. Navigates to the URL

  2. Runs full accessibility audit

  3. Tests specified section with auto-discovery or custom steps

  4. Generates human-readable report with:

    • Executive summary

    • Critical/serious/moderate/minor issues

    • Prioritized fix recommendations

Available Tools

1. a11y_scanUrl

Scan a URL for accessibility violations.

Parameters:

{
  url: string;              // Required: URL to scan
  selector?: string;        // Optional: CSS selector to scan specific element
  waitForSelector?: string; // Optional: Wait for this element before scanning
  captureScreenshot?: boolean; // Optional: Capture screenshot (default: false)
  timeout?: number;         // Optional: Navigation timeout in ms (default: 30000)
}

Example:

{
  "url": "https://example.com",
  "selector": "header nav",
  "captureScreenshot": true
}

2. a11y_scanInteractiveByText

Test components using natural language - no CSS selectors needed!

Parameters:

{
  url: string;              // Required: URL to navigate to
  containerText: string;    // Required: Visible text to find section (e.g., "Rewards")
  autoDiscover?: boolean;   // Optional: Auto-discover interactions (default: true)
  customInteractions?: Array<{
    stateName: string;      // Name for this interaction
    elementText: string;    // Visible text of element to interact with
    action: "click" | "hover" | "focus";
    waitAfter?: number;     // Wait time in ms (default: 500)
  }>;
  captureScreenshots?: boolean; // Optional: Screenshot each state
  timeout?: number;         // Optional: Navigation timeout in ms
}

Example: Auto-discover everything

{
  "url": "https://example.com",
  "containerText": "User Menu",
  "autoDiscover": true,
  "captureScreenshots": true
}

Example: Custom interactions

{
  "url": "https://example.com",
  "containerText": "Rewards",
  "customInteractions": [
    {
      "stateName": "After opening menu",
      "elementText": "View Details",
      "action": "click"
    }
  ]
}

Response Format

Scan Result

{
  "url": "https://example.com",
  "timestamp": "2025-01-28T...",
  "summary": {
    "violations": 3,
    "passes": 12,
    "incomplete": 1
  },
  "violations": [
    {
      "id": "color-contrast",
      "impact": "serious",
      "description": "Elements must have sufficient color contrast",
      "help": "Ensure contrast ratio is at least 4.5:1",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.4/color-contrast",
      "tags": ["wcag2aa", "wcag21aa"],
      "nodes": [
        {
          "html": "<button class=\"btn\">Submit</button>",
          "target": [".btn"],
          "failureSummary": "..."
        }
      ]
    }
  ],
  "screenshotPath": "/path/to/screenshot.png"
}

Interactive Scan Result

{
  "url": "https://example.com",
  "containerText": "Rewards",
  "totalStates": 3,
  "states": [
    {
      "stateName": "Initial State",
      "summary": {"violations": 0, "passes": 5, "incomplete": 0},
      "violations": []
    },
    {
      "stateName": "After interacting with buttons: \"View Details\"",
      "action": "click",
      "elementText": "View Details",
      "summary": {"violations": 2, "passes": 8, "incomplete": 1},
      "violations": [...]
    }
  ]
}

Project Structure

server/
├── constants/          # Configuration and constants
│   ├── config.ts      # Application configuration
│   ├── selectors.ts   # Interactive element selectors
│   └── wcag-tags.ts   # WCAG compliance tags
├── types/             # TypeScript type definitions
│   └── scan-result.ts # Scan result interfaces
├── utils/             # Utility functions
│   ├── axe-scanner.ts      # Axe configuration and scanning
│   ├── browser.ts          # Browser management
│   ├── container-finder.ts # Find elements by text
│   └── screenshot.ts       # Screenshot utilities
├── tools/             # Tool implementations
│   ├── scan-url.ts                   # URL scanning tool
│   └── scan-interactive-by-text.ts   # Interactive testing tool
├── prompts/           # Prompt templates
│   └── comprehensive-a11y-test.ts    # Predefined test prompt
└── server.ts          # Main MCP server entry point

WCAG Compliance

This server tests for:

  • WCAG 2.0 Level A (wcag2a)

  • WCAG 2.0 Level AA (wcag2aa)

  • WCAG 2.1 Level A (wcag21a)

  • WCAG 2.1 Level AA (wcag21aa)

  • Best Practices (best-practice)

Impact Levels

Violations are categorized by severity:

  • Critical: Blocks access completely - fix immediately

  • Serious: Creates significant barriers - fix before release

  • Moderate: Noticeable issues - fix soon

  • Minor: Small improvements - can be backlogged

Output Files

All screenshots are saved to: ./accessibility-screenshots/

  • scan-{timestamp}.png - Full page screenshots

  • {name}-{timestamp}.png - Named screenshots

Usage Examples

Test a simple page

User: "Check accessibility of https://example.com"
Claude: → Calls a11y_scanUrl
        → Returns: 3 violations (2 serious, 1 moderate)

Test specific section by name

User: "Test the Navigation menu on https://example.com"
Claude: → Calls a11y_scanInteractiveByText with containerText="Navigation"
        → Auto-discovers all interactive elements
        → Returns: Issues found in different states

Test with custom interactions

User: "Test the Rewards section - click 'View Details' then 'Redeem'"
Claude: → Parses your request
        → Calls a11y_scanInteractiveByText with custom interactions
        → Returns: Accessibility analysis for each state

Development

# Build TypeScript
npm run build

# Watch mode for development
npm run watch

# Start server directly (for testing)
npm start

Adding New Tools

  1. Create tool file in server/tools/

  2. Define schema and execution function

  3. Register in server/server.ts

Adding New Utilities

  1. Create utility file in server/utils/

  2. Export functions

  3. Import where needed

Best Practices

  1. Always test with screenshots during initial development:

    {"captureScreenshot": true}
  2. Wait for dynamic content on SPAs:

    {"waitForSelector": ".content-loaded"}
  3. Test interactive components in different states:

    • Initial state

    • After user interaction

    • Error states

    • Success states

  4. Use natural language testing when you don't know selectors:

    {"containerText": "User Menu", "autoDiscover": true}

Troubleshooting

Server not starting

npm run build
# Check config path is absolute
# Restart MCP client

Element not found

  • Verify the text exists on the page

  • Try a shorter, more specific text

  • Check if content is loaded (use waitForSelector)

Timeout errors

{"timeout": 60000}  // Increase to 60 seconds

Requirements

  • Node.js 18+

  • Playwright (browsers installed automatically)

License

ISC

Contributing

  1. Follow the modular architecture

  2. Add TypeScript types for new features

  3. Document new tools in README

  4. Update constants instead of hardcoding values


Built for production use with modular, maintainable architecture.

Available Tools

2 tools
a11y_scanInteractiveByTextA

Test accessibility of components by finding them using visible text/labels instead of CSS selectors. Automatically discovers and tests interactive elements. Perfect for natural language testing like 'test the Rewards section' or 'test the user menu'. Uses comprehensive WCAG 2.0, 2.1 Level A/AA and best-practice rules by default.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesURL to navigate to
containerTextYesVisible text to find the container by (e.g., 'Rewards', 'Navigation', 'User Profile'). Will search for this text in headings, labels, buttons, and ARIA labels.
autoDiscoverNoAutomatically discover and test all interactive elements (buttons, links, inputs) within the container
customInteractionsNoOptional custom interactions in addition to auto-discovery
captureScreenshotsNo
timeoutNo

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes key behaviors: 'Automatically discovers and tests interactive elements' and 'Uses comprehensive WCAG 2.0, 2.1 Level A/AA and best-practice rules by default.' However, it lacks details on permissions, rate limits, error handling, or what the test results look like (especially since there's no output schema).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the main purpose, followed by usage examples and default rules. Every sentence adds value: the first defines the tool, the second explains automation, the third gives usage context, and the fourth specifies standards. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, no annotations, no output schema), the description is incomplete. It covers the 'what' and 'when' well but lacks details on behavioral traits (e.g., what happens during testing, error scenarios) and output format. Without an output schema, the description should ideally hint at return values.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 67%, and the description adds meaningful context beyond the schema. It explains the core concept: 'finding them using visible text/labels' and 'automatically discovers and tests interactive elements,' which clarifies the purpose of containerText and autoDiscover parameters. However, it doesn't detail all six parameters (e.g., customInteractions, captureScreenshots).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Test accessibility of components by finding them using visible text/labels instead of CSS selectors. Automatically discovers and tests interactive elements.' It specifies the verb ('test accessibility'), resource ('components'), and method ('by finding them using visible text/labels'), and distinguishes it from sibling a11y_scanUrl by emphasizing text-based discovery rather than URL-only scanning.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: 'Perfect for natural language testing like 'test the Rewards section' or 'test the user menu'.' It implies usage for testing specific UI sections identified by text, but does not explicitly state when not to use it or name alternatives (e.g., when to use a11y_scanUrl instead).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

a11y_scanUrlA

Run accessibility scan on a URL or specific element using Playwright + axe-core. Supports full page or targeted section scanning with optional screenshots. Uses comprehensive WCAG 2.0, 2.1 Level A/AA and best-practice rules by default.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesURL to scan for accessibility issues
selectorNoCSS selector to scan only a specific section/element (e.g., 'header', '.main-content', '#navigation')
waitForSelectorNoCSS selector to wait for before scanning (useful for dynamic content)
captureScreenshotNoCapture screenshot of the scanned area with violations highlighted
timeoutNoNavigation timeout in milliseconds

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses some behavioral traits: it uses 'comprehensive WCAG 2.0, 2.1 Level A/AA and best-practice rules by default,' which indicates the scanning standards. However, it does not mention performance aspects (e.g., rate limits), authentication needs, or what happens if scanning fails. The description adds context but does not fully compensate for the lack of annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized with two sentences that efficiently convey key information: the core functionality and the scanning standards. It is front-loaded with the main purpose. However, the second sentence could be slightly more concise, and there is minor redundancy (e.g., 'comprehensive' might be implied).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (accessibility scanning tool with 5 parameters), no annotations, and no output schema, the description is moderately complete. It covers the purpose, technology, and standards but lacks details on output format, error handling, or integration context. It should do more to compensate for the missing structured data, especially for a tool with multiple parameters and no output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal value beyond the schema by mentioning 'optional screenshots' (related to captureScreenshot) and 'supports full page or targeted section scanning' (related to selector), but it does not provide additional syntax, format, or usage details. Baseline 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Run accessibility scan on a URL or specific element using Playwright + axe-core.' It specifies the verb ('scan'), resource ('URL or specific element'), technology stack ('Playwright + axe-core'), and scope ('full page or targeted section'). It distinguishes from the sibling tool 'a11y_scanInteractiveByText' by focusing on URL-based scanning rather than interactive text-based scanning.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context by mentioning 'full page or targeted section scanning' and 'optional screenshots,' but it does not explicitly state when to use this tool versus the sibling 'a11y_scanInteractiveByText' or other alternatives. It provides some guidance on capabilities (e.g., supports dynamic content via waitForSelector) but lacks explicit when/when-not instructions or named alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 2 tool updatesv1.0.0
    • First observeda11y_scanInteractiveByText
    • First observeda11y_scanUrl

TDQS

A3.8/5.0
Disambiguation4/5

The two tools have clearly distinct purposes: a11y_scanInteractiveByText focuses on testing components via visible text/labels for natural language scenarios, while a11y_scanUrl handles URL-based or element-specific scanning. There is minor potential for confusion since both perform accessibility scans, but their different input methods (text vs. URL/element) and use cases (interactive components vs. general pages) make them mostly distinguishable.

Naming Consistency5/5

Both tools follow a consistent naming pattern with the prefix 'a11y_scan' followed by descriptive suffixes (InteractiveByText and Url). They use snake_case uniformly, and the names clearly indicate their distinct functionalities, making them predictable and easy to understand.

Tool Count3/5

With only two tools, the server feels thin for an accessibility testing domain, which might involve more operations like generating reports, filtering results, or testing specific WCAG criteria. However, the tools cover core scanning functionalities, so it's borderline but not severely lacking.

Completeness3/5

The server provides basic scanning capabilities for URLs and interactive components, but there are notable gaps. Missing operations include result analysis tools (e.g., summarize findings, export reports), configuration options (e.g., custom rule sets), and follow-up actions (e.g., retest after fixes). This limits agents to scanning without deeper workflow support.

Maintenance

ActivityInactive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PashaBoiko/playwright-axe-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server