Server definition
- Hash
- sha256:7869d6ac93e3f2952a2a574ea70f2659fb2508ac79212b10108dc0cedc664a40
- What it is
- What a remote MCP server returned when asked what it offers: 13 tools
The blob, as servednamed by its sha256
{
"instructions": "WebAbility is a web accessibility platform — AI-powered widget, scanner, and agents for WCAG 2.2 / ADA / Section 508 / EAA compliance. https://webability.io\n\nThis is **WebAbility MCP** (hosted Full). Free for everyone. Scan and check tools work with no account or key, under fair-use limits per IP. A free WebAbility account (sign-in prompted by your client) unlocks `visual_audit`, `start_audit` and `get_audit`.\n\n## Engines used by scan_page\n- WebAbility detectors (60+ rules — gradient-aware contrast, weak names, decorative-icon detection, etc.)\n- axe-core (104 rules)\n- HTML_CodeSniffer (200+ rules)\nResults from all three are deduplicated into one issue list.\n\n## Three-tier output (since v1.2.1, mirrors axe-core)\n`scan_page` and `flow_scan` return (`scan_html` is axe-only and returns raw violations):\n- **issues**: high-confidence violations — safe to act on\n- **incomplete**: needs human review — DO NOT auto-fix these. Common causes: contrast against gradient/image backgrounds, marketing-image alt text, framer-motion pre-animation states.\n- **summary**: counts by severity + an `incomplete` count\nWhen proposing fixes to the user, treat `incomplete` items as questions, not bugs.\n\n## Structured fixes (since v1.6.0)\nEvery issue carries `fix.op` from a closed set — `add-attribute`, `set-attribute`, `remove-attribute`, `add-element`, `remove-element`, `add-text-content`, `suggest` — plus `fix.attribute` / `fix.value` when known, and a top-level `fixability`:\n- **mechanical**: the value is known — apply it as given\n- **contextual**: the op is known, the VALUE needs judgment (alt text, a label) — read `html` and `message`, then write it\n- **visual**: needs rendered output (contrast, focus ring, target size) — propose, never auto-apply\nOn React ≤18 / Vue dev builds each issue also carries `source` (`{file, line, column, component}`) read from the live component tree — open that file directly instead of calling find_source. Pass `sourceRoot` (local only) to get `sourceCandidates[]` for production builds.\n\n## Output controls (every scan tool)\n`minImpact`, `rules[]`, `wcag[]` narrow the result; `format: \"compact\"` prints one line per element with rule metadata once — use it by default in a coding loop, it is a fraction of the tokens.\n\n## Tool routing\n- \"Scan this page / URL / localhost\" → `scan_page`\n- \"Walk through login → checkout\" → `flow_scan` with `autoNavigate`\n- \"What does this WCAG rule check\" → `get_rules`\n- \"Suggest a fix for this issue\" → `detect_framework` then `generate_ai_fix`\n- \"Did my fix work?\" → `verify_fix` (after you edit the code AND serve the change — closes scan → fix → verify)\n- \"What changed since the last scan / did I introduce regressions?\" → `diff_scan` (baseline vs current → fixed / new / remaining)\n- \"Check this contrast pair\" → `check_color_contrast` (pass `url` to get brand-aligned suggestions)\n- \"Find where this selector lives in code\" → `find_source` (Lite / local only)\n- \"Validate this HTML snippet / a component's markup\" → `scan_html` (in-process, milliseconds, no browser — structural rules only; `engine: \"browser\"` for contrast) or `check_aria`\n- \"Give me a shareable report of these findings\" → `generate_report_pdf` (Lite / local only)\n- \"Catch issues axe misses (icon contrast, focus visibility, look-but-not-button)\" → `visual_audit` (free with account)\n- \"I need a report to hand to a compliance officer / legal\" → `start_audit`, then poll `get_audit` (free with account)\n- `find_source` / `scan_history` / `generate_report_pdf` are not available on the hosted server\n\n## Important\n- The core loop: `scan_page` → `detect_framework` → `generate_ai_fix` → edit source → `verify_fix`.\n- Generated fix code edits the user's source — confirm before applying.\n- The widget runtime applies its own client-side patches at runtime; do not duplicate those edits in source code.",
"tools": [
{
"description": "Validate ARIA attribute + accessible name/role/value usage in an HTML snippet. Runs axe-core `cat.aria` and `cat.name-role-value` rules (aria-* attribute correctness, role validity, required parents/children, aria-hidden-focus, accessible names). Returns `violations` (high-confidence) and `incomplete` (needs human review, e.g. dangling ARIA references — do NOT auto-fix). Nodes cap at 5 per rule by default — every rule reports nodesTotal + truncated; raise nodeLimit (max 50).",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"html": {
"description": "HTML to test for ARIA correctness",
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"nodeLimit": {
"description": "Max nodes returned per rule (default 5, max 50)",
"type": "number"
}
},
"required": [
"html"
],
"type": "object"
},
"name": "check_aria",
"outputSchema": null
},
{
"description": "Check a foreground/background color pair against WCAG contrast thresholds. When it fails, suggests BRAND-aligned replacements — extracts the actual brand palette from a live URL using our scanner (CSS vars + most-used colors), or use a provided `brandColors` array. No `url` and no `brandColors` = ratio + pass/fail only. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"background": {
"description": "Background color (hex or rgb)",
"type": "string"
},
"brandColors": {
"description": "Pre-supplied brand palette. Skips URL extraction if provided.",
"items": {
"type": "string"
},
"type": "array"
},
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"fontSize": {
"description": "Font size in px (default 16)",
"type": "number"
},
"foreground": {
"description": "Foreground color (hex or rgb)",
"type": "string"
},
"isBold": {
"description": "Whether text is bold (default false)",
"type": "boolean"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "Live URL to extract brand palette from (uses our scanner — CSS vars + dominant colors).",
"type": "string"
}
},
"required": [
"foreground",
"background"
],
"type": "object"
},
"name": "check_color_contrast",
"outputSchema": null
},
{
"description": "Detect which framework/stack a page uses (Tailwind, MUI, Bootstrap, WordPress, Next.js, plain CSS). Use before generate_ai_fix to get framework-appropriate code. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL to inspect",
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"name": "detect_framework",
"outputSchema": null
},
{
"description": "Compare two scans of the same page and report what changed: `fixed[]` (in the baseline, gone now), `new[]` (regressions — not in the baseline, present now), `remaining[]` (still there). Page-level complement to verify_fix (one element). Baseline is a scan_history id (`baselineId`, local installs) or a live scan of `baselineUrl`; current is `url` (scanned live now) or another history id (`currentId`). Findings are matched by issue id (rule + element), so a changed class/id on a fixed element reads as fixed AND new — check `new[]` before calling it a regression. Needs-review findings are diffed separately (`incompleteResolved` / `incompleteNew`) and never counted as fixed. Typical loop: scan_page → edit → diff_scan(baselineId=<that scan id>, url=<same url>) → confirm new[] is empty. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"baselineId": {
"description": "scan_history id of the BASELINE scan (local installs only)",
"type": "string"
},
"baselineUrl": {
"description": "Scan this URL live as the baseline (e.g. production) — use when there is no stored baseline",
"type": "string"
},
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"currentId": {
"description": "scan_history id to use as the CURRENT side instead of scanning `url`",
"type": "string"
},
"format": {
"description": "\"compact\" prints one line per element with rule metadata once. \"json\" returns every field (html, fix values, source). Default: JSON when it fits inline (under ~24k chars), otherwise compact plus a JSON summary of every count.",
"enum": [
"json",
"compact"
],
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"minImpact": {
"description": "Only findings at this severity or above (critical > serious > moderate > minor)",
"enum": [
"critical",
"serious",
"moderate",
"minor"
],
"type": "string"
},
"rootSelector": {
"description": "CSS selector to limit live scans to (optional)",
"type": "string"
},
"rules": {
"description": "Only these rule ids (WebAbility type such as \"missing_alt\" or axe rule id such as \"image-alt\"). See get_rules.",
"items": {
"type": "string"
},
"type": "array"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL to scan now as the CURRENT side (deployed, staging, or http://localhost:3000). Omit when passing currentId.",
"type": "string"
},
"viewport": {
"description": "Viewport for live scans (default: desktop). Use the same viewport the baseline used.",
"enum": [
"desktop",
"tablet",
"mobile"
],
"type": "string"
},
"wcag": {
"description": "Only these WCAG criteria. A prefix selects the whole guideline (\"1.4\") or principle (\"2\").",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [],
"type": "object"
},
"name": "diff_scan",
"outputSchema": null
},
{
"description": "Scan a multi-page user journey. Walks startUrl plus the required `autoNavigate` URLs sequentially (deterministic — one page fully rendered and scanned before the next), then returns ONE consolidated report with issues deduplicated across pages, each carrying the same fix payload / confidence / review flags as scan_page. Every requested URL gets an explicit outcome in `pages[]` (scanned / nav_failed / scan_failed / redirected_duplicate / duplicate_request / skipped_cap / blocked — bot-challenge, not a clean page) — a page is never silently dropped. Better than per-page scans for journeys (login → checkout etc). For a single page, use scan_page. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"autoNavigate": {
"description": "REQUIRED — the URLs to walk after startUrl (the MCP server is headless and cannot discover a journey interactively). For a single page, use scan_page instead.",
"items": {
"type": "string"
},
"type": "array"
},
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"format": {
"description": "\"compact\" prints one line per element with rule metadata once. \"json\" returns every field (html, fix values, source). Default: JSON when it fits inline (under ~24k chars), otherwise compact plus a JSON summary of every count.",
"enum": [
"json",
"compact"
],
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"maxPages": {
"description": "Max pages to scan (default 10)",
"type": "number"
},
"minImpact": {
"description": "Only findings at this severity or above (critical > serious > moderate > minor)",
"enum": [
"critical",
"serious",
"moderate",
"minor"
],
"type": "string"
},
"rules": {
"description": "Only these rule ids (WebAbility type such as \"missing_alt\" or axe rule id such as \"image-alt\"). See get_rules.",
"items": {
"type": "string"
},
"type": "array"
},
"sourceRoot": {
"description": "Local project root (local installs only) for `sourceCandidates[]` on issues without a framework `source` pointer.",
"type": "string"
},
"startUrl": {
"description": "Starting URL of the journey",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"wcag": {
"description": "Only these WCAG criteria. A prefix selects the whole guideline (\"1.4\") or principle (\"2\").",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"startUrl",
"autoNavigate"
],
"type": "object"
},
"name": "flow_scan",
"outputSchema": null
},
{
"description": "Generate framework-aware fix alternatives for a specific accessibility issue. For color contrast issues, returns 3 alternatives (minimal, brand-aligned, high contrast); brand palette is auto-extracted from the live URL using our scanner if `brandColors` is omitted. For label/ARIA issues, returns 1-2 alternatives. Each alternative includes ready-to-paste code for the detected framework. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"brandColors": {
"description": "Brand palette for brand-aligned suggestions. If omitted on a contrast issue with a `url`, auto-extracted via the scanner.",
"items": {
"type": "string"
},
"type": "array"
},
"context": {
"description": "Parent element outerHTML for context (~400 chars)",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"framework": {
"description": "CSS framework — use detect_framework first",
"enum": [
"tailwind",
"bootstrap",
"mui",
"wordpress",
"nextjs",
"plain-css"
],
"type": "string"
},
"html": {
"description": "The element's outerHTML — send at most ~600 chars",
"type": "string"
},
"issue": {
"description": "Issue object from scan_page (with selector, wcag, impact, message, fix.currentValue), or a plain-text issue description",
"type": [
"object",
"string"
]
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "Page URL — also used to auto-extract brand palette for contrast issues if `brandColors` is not provided.",
"type": "string"
}
},
"required": [
"issue",
"html",
"framework"
],
"type": "object"
},
"name": "generate_ai_fix",
"outputSchema": null
},
{
"description": "Check an audit started with start_audit: returns overall status, per-step progress (scan → viewports → screenshots → agent → excel → publish), and — once complete — a severity summary plus short-lived download URLs for the report (JSON) and the Excel workbook. Poll every ~15s while status is pending/running. Only the account that started an audit can read it. Free with a WebAbility account.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"id": {
"description": "The audit id returned by start_audit",
"type": "number"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "get_audit",
"outputSchema": null
},
{
"description": "List accessibility rules from both engines — axe-core (104) and the WebAbility detectors (90+) — with optional filters. Every rule carries `fixability` (mechanical | contextual | visual) and a `fix` op template, so you can pick the rules worth auto-fixing before scanning. Returns ruleId, engine, description, help, helpUrl, tags/wcag, fixability, fix.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"engine": {
"description": "Which engine's rules to list (default all)",
"enum": [
"all",
"axe",
"webability"
],
"type": "string"
},
"fixability": {
"description": "Only rules of this fixability tier",
"enum": [
"mechanical",
"contextual",
"visual"
],
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"rule": {
"description": "Only rules whose id contains this text (e.g. \"color-contrast\", \"label\"; case and -/_ insensitive). Also accepted: ruleId, id, query.",
"type": "string"
},
"tags": {
"description": "axe tag filter (e.g. [\"wcag21aa\"], [\"best-practice\"], [\"cat.aria\"]). WebAbility rules match on their WCAG criterion tag (e.g. \"wcag143\").",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [],
"type": "object"
},
"name": "get_rules",
"outputSchema": null
},
{
"description": "Scan a raw HTML snippet or component markup without serving it — IN-PROCESS by default (jsdom + WebAbility detectors + axe-core): milliseconds, no browser, no network, so it fits inside a tight edit loop. Fragments are auto-wrapped into a document. Returns scan_page's three-tier shape (issues / incomplete / summary) with `fix.op` + `fixability` on every finding. jsdom has no layout, so visual-tier rules (contrast, target size, focus ring) are NOT evaluated — the dropped count is reported as `skippedVisual`; pass `engine: \"browser\"` to run the axe-core headless-browser path for those (slower, axe rules only, returns axe `violations`).",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"engine": {
"description": "\"in-process\" (default): jsdom, ms, structural rules. \"browser\": headless Chromium + axe-core, includes contrast.",
"enum": [
"in-process",
"browser"
],
"type": "string"
},
"format": {
"description": "\"compact\" prints one line per element with rule metadata once. \"json\" returns every field (html, fix values, source). Default: JSON when it fits inline (under ~24k chars), otherwise compact plus a JSON summary of every count.",
"enum": [
"json",
"compact"
],
"type": "string"
},
"height": {
"description": "Viewport height (browser engine only, default 800)",
"type": "number"
},
"html": {
"description": "HTML content to test — a full document or a fragment",
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"minImpact": {
"description": "Only findings at this severity or above (critical > serious > moderate > minor)",
"enum": [
"critical",
"serious",
"moderate",
"minor"
],
"type": "string"
},
"rules": {
"description": "Only these rule ids (WebAbility type such as \"missing_alt\" or axe rule id such as \"image-alt\"). See get_rules.",
"items": {
"type": "string"
},
"type": "array"
},
"tags": {
"description": "WCAG tags to check (default [\"wcag2a\",\"wcag2aa\",\"wcag21aa\",\"wcag22aa\"])",
"items": {
"type": "string"
},
"type": "array"
},
"wcag": {
"description": "Only these WCAG criteria. A prefix selects the whole guideline (\"1.4\") or principle (\"2\").",
"items": {
"type": "string"
},
"type": "array"
},
"width": {
"description": "Viewport width (browser engine only, default 1280)",
"type": "number"
}
},
"required": [
"html"
],
"type": "object"
},
"name": "scan_html",
"outputSchema": null
},
{
"description": "Scan a web page for WCAG accessibility issues. Works on any URL — deployed sites, localhost, staging. Returns the three-tier shape: `issues` (high-confidence violations safe to fix), `incomplete` (needs human review — gradient backgrounds, marketing imagery, axe-incomplete results, framer-motion pre-animation states), and a `summary`. Treat `incomplete` as questions, never auto-fix them. On React ≤18 / Vue dev builds each issue carries `source` ({file, line, column, component}) read from the live component tree. Every issue carries a structured `fix.op` (add-attribute | set-attribute | remove-attribute | add-element | remove-element | add-text-content | suggest) with `fix.attribute` / `fix.value` when known, and a `fixability` tier (mechanical = apply as given; contextual = op known, value needs judgment; visual = needs rendered output, propose only). NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"format": {
"description": "\"compact\" prints one line per element with rule metadata once. \"json\" returns every field (html, fix values, source). Default: JSON when it fits inline (under ~24k chars), otherwise compact plus a JSON summary of every count.",
"enum": [
"json",
"compact"
],
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"minImpact": {
"description": "Only findings at this severity or above (critical > serious > moderate > minor)",
"enum": [
"critical",
"serious",
"moderate",
"minor"
],
"type": "string"
},
"rootSelector": {
"description": "CSS selector to limit scan scope (optional)",
"type": "string"
},
"rules": {
"description": "Only these rule ids (WebAbility type such as \"missing_alt\" or axe rule id such as \"image-alt\"). See get_rules.",
"items": {
"type": "string"
},
"type": "array"
},
"sourceRoot": {
"description": "Local project root (local installs only). Issues without a framework `source` pointer get `sourceCandidates[]` — files whose contents match the selector's id/class/attribute tokens.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL to scan (e.g. https://example.com or http://localhost:3000)",
"type": "string"
},
"viewport": {
"description": "Viewport size (default: desktop)",
"enum": [
"desktop",
"tablet",
"mobile"
],
"type": "string"
},
"wcag": {
"description": "Only these WCAG criteria. A prefix selects the whole guideline (\"1.4\") or principle (\"2\").",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"url"
],
"type": "object"
},
"name": "scan_page",
"outputSchema": null
},
{
"description": "Kick off a FULL accessibility audit deliverable for a URL — a persistent, timestamped artifact, not an inline scan. Runs the server-side pipeline (axe + advanced checks + mobile viewports + annotated screenshots + optional agent spot-check) and produces a downloadable report and a formatted Excel workbook (Cover / Status / Barriers / ADA context sheets) stored durably. Returns immediately with an audit `id`; poll `get_audit` for progress and, when complete, download URLs. Use this when someone needs a durable artifact to attach as evidence of testing effort for a compliance officer or legal response — for iterating on code, use scan_page + verify_fix instead. Free for everyone; needs a free WebAbility account (sign in when your client prompts you, or run `webability login`). Set includeAgent:true to add the slower agentic manual-audit pass. To audit a local dev server, open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` with the printed secret as `tunnel_secret`; keep the tunnel open until get_audit reports complete (about 5 minutes) — the pipeline loads the page several times.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"includeAgent": {
"description": "Also run the agentic manual-audit pass (keyboard/focus/modal exploration). Slower. Default false.",
"type": "boolean"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL to audit (a public/staging URL the server can reach, or a webability-tunnel URL — not localhost)",
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"name": "start_audit",
"outputSchema": null
},
{
"description": "Re-scan a specific element after applying an accessibility fix and confirm the violation is gone — closes the loop that find-only tools leave open. After you edit the code and serve it (deployed, staging, or http://localhost:3000), call this with the URL and the selector you fixed to get a machine-checked verified: true|false (DOM engines only — visual_audit findings and needs-review items are out of scope). Pass the WCAG criterion (e.g. \"1.1.1\") or axe rule id (e.g. \"color-contrast\") to check just that criterion; omit it to require the element be clean of ALL violations. A blocked page (bot-challenge / HTTP error) is reported as unverified, never a pass — verification fails closed. IMPORTANT: if your fix changed the element's class or id, the original selector may no longer match anything, which reads as verified — re-run scan_page or pass the updated selector to be sure. Pair with scan_page → generate_ai_fix → verify_fix for a full find-fix-verify cycle. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"selector": {
"description": "CSS selector of the element you fixed — use the `selector` from the original scan_page issue",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL now serving the fix (deployed, staging, or http://localhost:3000). Also accepted as `page` or `pageUrl`.",
"type": "string"
},
"viewport": {
"description": "Viewport size (default: desktop). Use the same viewport the issue was found at.",
"enum": [
"desktop",
"tablet",
"mobile"
],
"type": "string"
},
"wcag": {
"description": "Optional: WCAG criterion (e.g. \"1.1.1\", \"1.4.3\") or axe rule id (e.g. \"color-contrast\") to verify specifically. Omit to require the element be free of ALL violations.",
"type": "string"
}
},
"required": [
"url",
"selector"
],
"type": "object"
},
"name": "verify_fix",
"outputSchema": null
},
{
"description": "Pixel-level accessibility audit using Claude vision. Catches issues that DOM scanners miss: icon contrast (1.4.11), focus visibility (2.4.7), \"looks like a button but isn't\" (4.1.2), text rendered as images (1.4.5), visual hierarchy mismatches. Takes a URL, opens it in a headless browser, screenshots, and runs vision-based detection. Complements scan_page — run both for full coverage. Free for everyone; sign in with a free WebAbility account for vision and full audits (sign in when your client prompts you, or run `webability login`). Fair-use rate limits apply. NOTE: on this HOSTED server, localhost and private addresses are refused — it runs in our cloud and cannot reach your machine. Two ways to scan a local dev server: run the MCP locally (`npx -y @webability/mcp`, simplest — nothing leaves the machine), or open a tunnel (`webability-tunnel --port 3000`) and pass its URL as `url` together with the printed secret as `tunnel_secret`.",
"inputSchema": {
"properties": {
"brandColors": {
"description": "Brand hex colors for context-aware filtering",
"items": {
"type": "string"
},
"type": "array"
},
"context": {
"description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"",
"type": "string"
},
"conversation_id": {
"description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.",
"type": "string"
},
"fullPage": {
"description": "Capture full scrolled page instead of just viewport (default: false)",
"type": "boolean"
},
"llm_model": {
"description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.",
"type": "string"
},
"tunnel_secret": {
"description": "Secret printed by `webability-tunnel`. Required when `url` is a tunnel URL; the URL alone will be refused by the relay. Ignored otherwise.",
"type": "string"
},
"url": {
"description": "URL to audit visually",
"type": "string"
},
"viewport": {
"description": "Viewport size (default: desktop)",
"enum": [
"desktop",
"tablet",
"mobile"
],
"type": "string"
}
},
"required": [
"url"
],
"type": "object"
},
"name": "visual_audit",
"outputSchema": null
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:7869d6ac93e3f2952a2a574ea70f2659fb2508ac79212b10108dc0cedc664a40 | sha256sum