Skip to main content
AccessibilityHub follows a modular architecture with clear separation of concerns. This guide explains the project structure and the role of each component.

Repository Structure

A-I-ccesibility/
├── src/                      # Source code
│   ├── server.ts               # MCP server entry point
│   ├── tools/                  # Accessibility analysis tools
│   ├── prompts/                # MCP prompt templates
│   ├── resources/              # MCP resources (WCAG data, thresholds)
│   └── shared/                 # Shared utilities across modules
├── tests/                    # Test files (mirrors src/ structure)
├── docs/                     # Documentation
├── scripts/                  # Build and utility scripts
├── .cursor/                  # Cursor IDE configuration
│   ├── commands/             # Cursor commands (e.g., create-tool)
│   └── rules/                # Project conventions
├── dist/                     # Compiled output (generated)
├── package.json
├── tsconfig.json
└── README.md

Core Directories

src/server.ts

Entry point for the MCP server
// Registers all tools, prompts, and resources
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { registerTools } from './tools';
import { registerPrompts } from './prompts';
import { registerResources } from './resources';

const server = new McpServer({
  name: 'accessibility-hub',
  version: '1.0.0'
});

registerTools(server);
registerPrompts(server);
registerResources(server);

server.start();
Responsibilities:
  • Initialize MCP server
  • Register all tools, prompts, and resources
  • Handle graceful shutdown
  • Set up error handling

src/tools/

Accessibility analysis tools
tools/
├── index.ts                # Exports all tools
├── Axe/                    # axe-core integration
├── Pa11y/                  # Pa11y integration
├── Lighthouse/             # Lighthouse integration
├── Contrast/               # Color contrast analysis
├── AnalyzeMixed/           # Combined multi-tool analysis
└── Base/                   # Shared base utilities
Available tools:
axe-core integration
  • Tool name: analyze-with-axe
  • Analyzes URLs or HTML with axe-core
  • Returns WCAG violations and incomplete checks
  • Fast execution (~2-3 seconds)
Exports:
  • analyzeWithAxeTool: Tool definition
  • disposeAxeAdapter: Cleanup function
Pa11y integration
  • Tool name: analyze-with-pa11y
  • HTML structure and semantic validation
  • Uses HTML CodeSniffer rules
  • Fast execution (~2 seconds)
Exports:
  • analyzeWithPa11yTool: Tool definition
  • disposePa11yAdapter: Cleanup function
Lighthouse integration
  • Tool name: analyze-with-lighthouse
  • Provides accessibility score (0-100)
  • Detailed audit results
  • Slower execution (~5-10 seconds)
Exports:
  • analyzeWithLighthouseTool: Tool definition
  • disposeLighthouseAdapter: Cleanup function
Color contrast analysis
  • Tool name: analyze-contrast
  • WCAG 2.1 and APCA support
  • Suggests compliant color fixes
  • Very fast (~1-2 seconds)
Exports:
  • analyzeContrastTool: Tool definition
  • disposeContrastAdapter: Cleanup function
Combined multi-tool analysis
  • Tool name: analyze-mixed
  • Runs axe-core, Pa11y, and Lighthouse in parallel
  • Deduplicates common issues
  • Returns unified results
Exports:
  • analyzeMixedTool: Tool definition
  • disposeAnalyzeMixedAdapters: Cleanup function
Shared base utilities
  • Common types and interfaces
  • Base adapters and normalizers
  • Utility functions used by all tools
Exports:
  • ToolDefinition: Base tool interface
  • createJsonResponse: Response helpers
  • withToolContext: Tool execution wrapper

Tool Structure

Each tool follows a consistent modular structure:
ToolName/
├── index.ts           # Public exports
├── main.ts            # Main logic, MCP registration, handlers
├── adapters/          # External library integrations
│   ├── toolname.adapter.ts
│   └── index.ts
├── normalizers/       # Input/output data transformation
│   ├── toolname.normalizer.ts
│   └── index.ts
├── types/             # TypeScript types and interfaces
│   ├── toolname.type.ts
│   └── index.ts
└── utils/             # Helper functions
    ├── toolname.utils.ts
    └── index.ts
1

index.ts

Public exports
export * from './main.js';
export * from './types/index.js';
  • Only re-exports, never contains logic
  • Defines public API surface
2

main.ts

Main tool logic
export const analyzeWithAxeTool: ToolDefinition = {
  name: 'analyze-with-axe',
  description: 'Analyze with axe-core...',
  inputSchema: AxeToolInputSchema,
  handler: async (input) => {
    // Tool implementation
  }
};
  • MCP tool registration
  • Request handlers
  • Coordinates adapters, normalizers, utils
3

adapters/

External library wrappers
export class AxeAdapter {
  async analyze(target, options) {
    // Wrap axe-core library
  }
}
  • Abstract external dependencies
  • Handle library initialization
  • Manage resources (browsers, etc.)
4

normalizers/

Data transformation
export function normalizeAxeResult(raw: AxeResults): NormalizedResult {
  // Transform axe-core output to standard format
  // Add enriched context
}
  • Input validation and transformation
  • Output standardization
  • Enrichment with WCAG context
5

types/

Type definitions
export interface AxeToolInput {
  url?: string;
  html?: string;
  options?: AxeOptions;
}

export const AxeToolInputSchema = z.object({
  url: z.string().optional(),
  html: z.string().optional(),
  options: z.object({...}).optional()
});
  • TypeScript interfaces
  • Zod schemas for validation
  • Enums and constants
6

utils/

Helper functions
export function buildAnalysisTarget(input) {
  return input.url ? { type: 'url', value: input.url }
                   : { type: 'html', value: input.html };
}
  • Pure utility functions
  • Tool-specific helpers
  • Formatting and conversion

src/prompts/

MCP prompt templates for common workflows
prompts/
├── index.ts                # Exports all prompts
├── audit/                  # Audit prompts
│   ├── full-accessibility-audit.ts
│   ├── quick-accessibility-check.ts
│   └── pre-deploy-check.ts
├── contrast/               # Contrast prompts
│   └── contrast-check.ts
├── educational/            # Educational prompts
│   └── explain-wcag-criterion.ts
├── workflows/              # Workflow prompts
│   └── quick-wins-report.ts
└── types/                  # Prompt type definitions
    └── index.ts
Prompt structure:
export const fullAccessibilityAuditPrompt: PromptDefinition = {
  name: 'full-accessibility-audit',
  description: 'Comprehensive accessibility audit',
  arguments: [
    {
      name: 'url',
      description: 'URL to analyze',
      required: true
    },
    {
      name: 'wcagLevel',
      description: 'WCAG level (A, AA, AAA)',
      required: false
    }
  ],
  handler: async (args) => {
    return {
      messages: [
        {
          role: 'user',
          content: `Perform a comprehensive accessibility audit...
          
          Use analyze-mixed to test ${args.url}...
          `
        }
      ]
    };
  }
};

src/resources/

MCP resources providing reference data
resources/
├── index.ts                # Exports all resources
├── wcag/                   # WCAG criteria data
│   ├── wcag-criteria.resource.ts
│   └── index.ts
├── contrast/               # Contrast threshold data
│   ├── contrast-thresholds.resource.ts
│   └── index.ts
├── lighthouse/             # Lighthouse audit catalog
│   ├── lighthouse-audits.resource.ts
│   └── index.ts
└── types/                  # Resource type definitions
    └── index.ts
Resource URIs:
  • wcag://criteria - All WCAG criteria
  • wcag://criteria/{criterion} - Specific criterion (e.g., 1.1.1)
  • contrast://thresholds/wcag21 - WCAG 2.1 thresholds
  • contrast://thresholds/apca - APCA thresholds
  • lighthouse://audits - Lighthouse audit catalog

src/shared/

Shared utilities across all modules
shared/
├── adapters/           # Base adapter classes
├── data/               # Static data (wcag-criteria.json)
├── normalizers/        # Common data normalizers
├── types/              # Shared type definitions
└── utils/              # Common utility functions
Key shared utilities:
{
  "1.1.1": {
    "criterion": "1.1.1",
    "level": "A",
    "principle": "perceivable",
    "title": "Non-text content",
    "description": "...",
    "userImpact": {
      "affectedUsers": ["screen-reader", "low-vision"],
      "impactDescription": "...",
      "realWorldExample": "..."
    },
    "remediation": {
      "effort": "low",
      "priority": "critical",
      "commonSolutions": ["..."]
    }
  }
}
Used for enriching issues with human context

Naming Conventions

Folders

PascalCase

Tool folders
  • Axe/
  • Pa11y/
  • AnalyzeMixed/
  • Lighthouse/

lowercase

Subfolders
  • adapters/
  • normalizers/
  • types/
  • utils/

Files

  • kebab-case or toolname.category.ts pattern
  • Examples: main.ts, pa11y.adapter.ts, axe.types.ts
  • Each subfolder has index.ts that re-exports
  • JSON files: wcag-criteria.json

Index Files

index.ts files should only re-export, never contain logic
// Good: index.ts only re-exports
export * from './pa11y.adapter.js';
export * from './pa11y.normalizer.js';

// Bad: index.ts contains logic
export function doSomething() {
  // Logic here
}

Module Responsibilities

ModuleResponsibility
server.tsMCP server initialization, registration of tools/prompts/resources
tools/Accessibility analysis tools, external library integration
prompts/Prompt templates for common workflows
resources/Read-only reference data (WCAG, thresholds)
shared/Common utilities, types, data used across modules
tests/Test files mirroring src/ structure
docs/User-facing documentation
scripts/Build and automation scripts

Data Flow

1

MCP Client Request

User sends request via MCP client (Claude Desktop, Cursor, etc.)
"Analyze the accessibility of https://example.com"
2

Tool Selection

MCP server routes to appropriate tool (e.g., analyze-mixed)
3

Input Validation

Tool validates input using Zod schema in types/
const validated = AnalyzeMixedInputSchema.parse(input);
4

Adapter Execution

Adapter calls external library (axe-core, Pa11y, Lighthouse)
const results = await Promise.all([
  axeAdapter.analyze(url),
  pa11yAdapter.analyze(url),
  lighthouseAdapter.analyze(url)
]);
5

Normalization

Normalizer transforms raw results to standard format
const normalized = normalizeResults(results);
6

Enrichment

Shared utilities add human context from WCAG data
const enriched = enrichWithWCAGContext(normalized);
7

Response

Tool returns formatted response to MCP client
return createJsonResponse(enriched);

Contributing Overview

Get started with contributing

Creating Tools

Guide for creating new tools

Build docs developers (and LLMs) love