
Tactual
io.github.tactual-dev由 GitHub 帳號 tactual-dev 發布v0.2.1更新於 Oct 24, 2026
Screen-reader navigation cost analyzer. Scores AT user effort to find, reach, and operate content.
概覽
Tactual 是一個本機 MCP 伺服器,用來分析網頁的螢幕閱讀器導覽成本,讓助理評估、追蹤並比較輔助技術使用者找到與操作內容所需付出的操作代價。
- 可以做什麼
- 在 NVDA、JAWS 或 VoiceOver 設定檔下分析單頁與多頁網站的螢幕閱讀器導覽成本,可選擇探索隱藏介面、選單、對話框與表單。追蹤抵達某個目標的逐步導覽路徑,並提供模擬的螢幕閱讀器朗讀內容。以虛擬螢幕閱讀器驗證預測路徑,並用校準資料集對照已儲存的分析結果。比較兩次分析結果的改善與退步,並取得依影響排序的修正建議。列出可用的輔助技術設定檔。
- 適用情境
- 適合網頁應用程式的無障礙工作:跨路由盤點導覽成本、查明某個控制項為何難以到達,以及透過基準線比對驗證修正前後的變化。適合希望取得有證據支撐的發現、而不只是合規檢查的開發者與無障礙審查人員。
- 執行需求
- 透過 npx tactual-mcp 或全域安裝以 stdio 在本機執行;需要 Node.js 20 或更新版本。頁面擷取依賴 Playwright 與 Chromium,因此需要可用的瀏覽器二進位檔。未宣告任何帳號、API 金鑰或環境變數。需要能存取被分析的網頁。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Tactual,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Tactual
Screen-reader navigation cost analyzer. Measures how many keystrokes a screen-reader user needs to discover, reach, and operate every interactive target on your page — under a specific AT profile (NVDA, JAWS, VoiceOver).
What it does
Existing accessibility tools check conformance — is the ARIA correct? Is the contrast ratio sufficient?
Tactual measures navigation cost — how many actions does it take a screen-reader user to reach the checkout button? What happens if they overshoot? Can they even discover it exists? Does the menu actually open on Enter, or only on click? Does focus land on the first menuitem or stay stuck on the trigger?
How it works:
- Captures Playwright accessibility snapshots + screen-reader announcement simulation
- Optionally explores hidden branches (menus, dialogs, tabs, disclosures) and probes them with real keyboard events, including APG-style widget contracts and form-error flows
- Builds a navigation graph with entry points (landmarks, headings, linear Tab) and scores every target
- Optionally validates predicted paths against
@guidepup/virtual-screen-readerfor calibration
Tactual is a developer tool for analyzing your own sites and staging environments. Run it locally, in CI, or via the MCP server in your editor. It is not a public scanning service.
How it fits
Tactual complements conformance scanners such as axe-core, Lighthouse, and Pa11y. Those tools are still the right first pass for broad WCAG and ARIA rule coverage. Tactual is aimed at the next question: after a page has valid markup, how expensive is it for an AT user to discover, reach, and operate the important targets?
Use Tactual for screen-reader navigation-cost triage, path tracing, measured keyboard/widget evidence, before/after diffs, CI prioritization, and MCP workflows where an agent needs compact findings with source selectors and remediation candidates. Use real screen readers and manual testing for final validation of critical journeys, timing-sensitive flows, browser/AT settings, and implementation patterns that intentionally differ from a common APG example.
Agent quick path: this README is a product overview plus reference. Agents should start with docs/AGENT-RECIPES.md for task patterns and docs/MCP-TOOLS.md for full MCP schemas, then come back here only for product context, install notes, and release-surface examples.
Install
Requires Node.js 20 or later.
Tactual installs Playwright as a runtime dependency so one-off npx tactual@latest ... commands work without separately installing Playwright into the npx cache. The MCP SDK also ships as a runtime dependency, so tactual-mcp works from an installed tactual package without a separate SDK install.
Quick start
CLI
Console output includes a compacted path line for each finding showing how a screen-reader user reaches it:
Where Tab = nextItem, H = nextHeading, ; = nextLandmark, K = nextLink, B = nextButton, Enter = activate. Consecutive same-action steps collapse (Tab ×2).
From Audit to Fix
For accessibility work in a local app or preview environment, Tactual supplies evidence for small, reviewable changes:
selector,penalties,suggestedFixes, and evidence summaries on each finding- grouped
issueGroupsand remediation candidates in summarized output analyze_pages.site.repeatedNavigationfor repeated navigation cost across routesdiff-results/diff_resultsfor before-and-after verification
Start with broad triage, then deepen one route before changing code:
Use the candidate section as a starting point for repeated root causes such as a shared component, navigation pattern, or widget contract. Confirm the source component and include the route, command, finding evidence, user impact, code change, and verification in whatever issue or PR format the project expects. Score movement is useful supporting evidence, but the change should lead with the accessibility behavior that changed.
MCP clients can consume the same compact output and keep the review loop grounded in routes, selectors, evidence, source changes, and before/after verification.
Library API
Screen-reader announcement simulator — predict what NVDA, JAWS, or VoiceOver would announce for every target, with state info (checked, expanded, selected, modal, value, required, invalid, etc.):
Validation and calibration APIs — compare model output against virtual-SR validation runs or human-observation datasets:
Or from the CLI:
The simulator is heuristic prediction, not real screen-reader output. The simulator itself is fast (pure JavaScript over captured targets — sub-second once targets are in memory), but a full analyze-url run includes browser launch + page capture + scoring and takes seconds on small pages, longer with --probe (~30s+) and --explore (~1–5 min on complex SPAs). Analysis runs in a headless browser by default, so nothing pops up while you work. (Use --no-headless or --channel chrome --stealth for visible/bot-protected sites.)
Data quality. Calibrated against token-level assertions from the W3C ARIA-AT project: 77/77 role/name/state-token assertions pass at 100% across all three ATs (NVDA, JAWS, VoiceOver), covering role/name/state phrasing for 36 single-target patterns (button, toggle button, all menu button variants, disclosure, accordion, checkbox/tri-state, switch, sliders, dialog, alert, links, tabs, comboboxes, radiogroups, spin button, menubar) plus 4 multi-target landmark scenarios. Run npm run calibrate after npm run build to verify against the latest upstream assertions. This is simulator calibration, not proof of full screen-reader fidelity across browse modes, verbosity settings, timing, or every valid widget variant. AT-specific overrides outside the calibrated set are labeled HIGH/MEDIUM/LOW confidence in the source.
MCP Server
Tactual includes an MCP server for AI agent consumption:
For network-facing MCP deployments, put the HTTP transport behind an authenticated TLS proxy and keep it scoped to trusted clients. See SECURITY.md for the hosted checklist and threat model.
MCP tools available:
Full parameter reference: docs/MCP-TOOLS.md
Setup by AI tool
First install the required packages in your project:
Claude Code — add to .mcp.json in your project root:
GitHub Copilot — add to .copilot/mcp.json or ~/.copilot/mcp-config.json:
Cursor / Windsurf / Cline — same format in your editor's MCP config:
Direct (global install) — if you prefer not to use npx:
GitHub Actions
Use the composite action from the GitHub Actions Marketplace:
The action installs Tactual and Chromium browser binaries, runs the analysis, uploads SARIF to GitHub Code Scanning, and fails the build if the average score is below the threshold. Set comment-on-pr: "true" to post a summary comment on pull requests (updates on re-run). Outputs average-score and result-file for downstream steps. Action version tracks Tactual version — bump the uses: line to pick up patches.
Defaults are conservative: probe is off unless enabled because it sends real keyboard events, and forced-colors icon checks run only for profiles that declare visualModes such as nvda-desktop-v0 and jaws-desktop-v0.
Or use the CLI directly for more control:
Regression gate (CI fail on worse-than-baseline)
Pair --baseline with --fail-on-regression to turn Tactual into a strict CI gate: save a baseline from a known-good build, then fail PR checks whenever a change regresses N+ findings vs the baseline. The diff-results command can also be run separately for human-readable before/after reports.
Or via the action:
The action mirrors the analyze-url CLI surface for analysis inputs, and a CI-to-CLI contract test keeps those fields aligned. Some workflow controls are Action orchestration rather than direct CLI flags: fail-below wraps CLI --threshold, comment-on-pr controls the PR comment step, and SARIF upload is handled by the workflow. The common inputs you'll set include profile, explore, explore-depth, explore-budget, explore-timeout, probe, probe-mode, probe-strategy, scope-selector, probe-selector, entry-selector, goal-target, goal-pattern, stealth, channel, wait-for-selector, exclude, exclude-selector, focus, min-severity, max-findings, baseline, fail-on-regression, fail-below, validate, storage-state, summary-only. The direct-CLI invocation pattern above is still the recommended path when you want a different Tactual version than the action pins.
Configuration
CLI flags
tactual.json
Create with tactual init or manually:
Config is auto-detected from the working directory (tactual.json or .tactualrc.json). CLI flags merge with and override config settings.
AT Profiles
Profiles define the cost of each navigation action, score dimension weights, costSensitivity (scales the reachability decay curve), and context-dependent modifiers. See src/profiles/ for implementation details.
Mobile profile limitation. The voiceover-ios-v0 and talkback-android-v0 profiles model action costs and SR announcement phrasing accurately, but Tactual's keyboard probes (--probe) only test desktop interactions (Tab, Enter, Escape). They do NOT simulate touch gestures (single-tap, double-tap, swipe-right, three-finger swipe, rotor rotation, etc.). For mobile profiles, score dimensions reflect predicted cost from the profile model — not measured behavior. Real device testing remains necessary to verify mobile a11y.
Visual modes. The nvda-desktop-v0 and jaws-desktop-v0 profiles declare a visualModes matrix (light/dark × forced-colors on/off) so the analyzer captures per-icon contrast under each combination. Mobile and generic profiles omit this — Windows High Contrast Mode isn't a realistic mobile concern. See Visibility checks below.
Visibility checks
When the active profile declares a visualModes matrix, Tactual re-emulates each (colorScheme, forcedColors) combination after the initial capture and samples per-icon computed styles. The finding builder compares each icon's computed fill against the nearest non-transparent ancestor background-color and emits a penalty when contrast falls below the WCAG 1.4.11 non-text threshold (3:1).
Four penalty wordings, three scoring tiers:
The check skips icons that are already HCM-safe: fill="currentColor", fill: ButtonText (or any system color), forced-color-adjust: none (author opt-out), or computed fill === color (CSS-applied currentColor). Low-contrast icons next to a visible text label are suppressed entirely — the label identifies the control and the icon is reinforcement.
Why the substitution-risk tier exists. Different user HCM themes have different Canvas/ButtonText/system-color values. An author literal fill (e.g. svg { fill: #e4e6e6 }) may contrast well against Chromium's default HCM palette but poorly against a specific user theme. Browser rendering of the literal itself is consistent across Playwright, Chrome, and Edge for forced-color-adjust: preserve-parent-color (the default for SVG paths) — the concrete concern is theme variability, not a hidden OS-paint substitution. Tactual flags the pattern so you know to verify in real Edge with a representative HCM theme, not because Playwright's contrast measurement is misleading.
Disable explicitly via --no-check-visibility, checkVisibility: false in tactual.json, or checkVisibility: false on the MCP analyze_url tool. Force-enable via --check-visibility even when a profile doesn't declare modes (no-op without modes).
The check adds roughly +50–200ms per declared mode per page — re-emulating media is cheap; there's no new browser context per mode.
Scoring Presets
Presets bundle focus filters and priority mappings for common use cases. They layer under config files and CLI flags (preset → tactual.json → CLI flags).
Presets suppress cookie banners and analytics targets by default. To override, use --exclude or set priority in tactual.json. Presets do not compose — only one --preset can be active.
Scoring
Each target receives a 5-dimension score vector:
Dimension weights vary by profile:
Composite: Weighted geometric mean: overall = exp(sum(w_i * ln(score_i)) / sum(w_i)) - interopRisk. Each dimension is floored at 1 before the log to avoid log(0). A zero in any dimension eliminates that dimension's contribution to the geometric mean, significantly dragging the overall score down -- you cannot operate what you cannot reach.
Severity bands:
Diagnostics
Tactual emits diagnostics for capture reliability, page structure, visual access, runtime evidence, ARIA validity, and repeated cost patterns. Warnings are review prompts, not automatic conformance failures. Many visual/content checks are heuristic and should be confirmed in context before filing a defect.
Exploration
The --explore flag activates bounded branch exploration:
- Opens menus, tabs, disclosures, accordions, and dialogs
- Captures new accessibility states from hidden UI
- Marks discovered targets as
requiresBranchOpen - Respects depth, action count, target count, and novelty budgets
- Safe-action policy blocks destructive interactions
Exploration is useful for pages with significant hidden UI (e.g., dropdown menus, tabbed interfaces, modal dialogs).
Exploration candidates are sorted by a stable key (role + name) before iterating, so the same page content produces the same exploration order across runs.
Probes
The --probe flag measures whether important interactive patterns work after they appear in the accessibility tree. Probes are opt-in because they send real keyboard events and add runtime. Since 0.4.0 this includes generic focus/activation checks, menu contracts, modal dialog contracts, trigger-to-dialog flows, tabs, disclosures, comboboxes, listboxes, and required-field error flows. Probe findings include evidence summaries so reports distinguish measured failures from modeled or heuristic scoring.
Goal-directed controls keep deep probes useful on complex SPAs:
For example, to evaluate a modal branch without crawling unrelated menus:
Exploration budgets
Sizing guidance:
If exploration hits the timeout before opening useful branches, raise --explore-timeout and --explore-budget slowly, or use --entry-selector, --probe-selector, and --probe-strategy to spend the same budget on the branch you care about. If output has duplicate-looking targets, lower --explore-depth (deep recursion can re-discover the same elements through different paths).
SPA framework detection
Tactual detects when SPA content has rendered before capturing the accessibility tree. Detected frameworks: React, Next.js, Vue, Nuxt, Angular, Svelte, and SvelteKit. Generic HTML5 content signals (landmarks, headings, navigation, links) are also checked. For SPAs not covered by auto-detection, use --wait-for-selector (CLI) or waitForSelector (MCP/API) to specify a CSS selector that indicates your app has hydrated.
After initial framework detection, Tactual uses convergence-based polling — repeatedly snapshotting the accessibility tree until the target count stabilizes — which works regardless of framework.
For SPA-heavy apps, these opt-in capture helpers are useful:
--detect-routesrecordspushState,replaceState,popstate, andhashchangeevents that happen during analysis.--auto-scrollsurfaces IntersectionObserver-driven lazy content before capture.--descend-framesappends iframe targets with frame URL attribution. Same-origin frames use Playwright's frame-scoped accessibility snapshot; Chromium falls back to CDP for cross-origin OOPIFs when the normal snapshot path is inaccessible. Firefox/WebKit keep the existing skip behavior for inaccessible frames.--diff-viewportscatches target, landmark, or heading content that disappears between desktop and mobile viewports.--dismiss-banners,--probe-hover, and--walk-tab-orderadd targeted runtime evidence for common SPA overlays and focus-order bugs.
Known-pages benchmark
For release evidence against complex public SPA/component-library pages, run:
The script builds the package, runs analyze-url with the SPA helper stack
enabled, and writes run-results.json, summary.json, and REPORT.md under
build/known-pages-*. It is intentionally not a CI gate: public sites change,
block automation, and serve different content over time. Use the report to spot
drift and category-level surprises, then use local fixtures or project-owned
pages for deterministic regression gates. For a bounded smoke run or APG/W3C
capture-quality probes, call the script directly, for example
node scripts/known-pages-corpus.mjs --build --limit 1 or
node scripts/known-pages-corpus.mjs --build --include-capture-probes.
Regression Tracking
Compare two analysis runs to catch regressions:
The diff shows targets that improved, regressed, or changed severity, plus penalties resolved and added. In CI, use the comment-on-pr action input to post results on every pull request automatically.
Interop Risk
Tactual includes a static snapshot of ARIA role/attribute support data derived from a11ysupport.io and the ARIA-AT project. Roles with known cross-AT/browser support gaps receive an interop risk penalty.
Interpreting Findings
Tactual findings intentionally mix several evidence domains:
- SR navigation: landmarks, headings, labels, branch discovery, sequential traversal cost, and modeled announcements.
- Keyboard operability: focus movement, activation, Escape recovery, Tab trapping, and runtime widget probes.
- Structural semantics: missing names, heading/landmark structure, demoted landmarks, repeated shared causes.
- Interop risk: roles and states with known cross-AT/browser support gaps.
- Pointer-adjacent checks: target-size and icon visibility issues that can affect users outside the screen-reader navigation model.
That means a page can have a strong screen-reader navigation score and still receive skip-link, target-size, or visibility warnings. Treat those as separate fix categories rather than contradictions.
Probe-derived APG findings are measured consistency warnings. Many widgets have valid implementation variants, especially comboboxes and disclosure-like patterns, so verify the warning against the intended pattern before treating it as a mandatory replacement. Critical flows should still be checked with the target browser/AT combination.
Output Format Recommendations
All non-SARIF reporter formats emit summarized output by default: stats, grouped issues, remediation candidates, evidence summaries, and worst findings (capped at 15). SARIF caps at 25 results. When output is truncated, a note appears at the top. The library API exposes the full AnalysisResult; CLI and MCP reporter output is intentionally compact unless a specific field such as includeStates is requested.
For MCP usage, sarif is the default and recommended format. Use summaryOnly: true for a compact health check with stats, severity counts, diagnostics, and the top 3 issues.
Calibration
Tactual includes a calibration framework (src/calibration/, exported as tactual/calibration) for tuning scoring parameters against ground-truth datasets. See docs/CALIBRATION.md for details.
Calibration observations can also include deterministic announcement feedback from OSS review work: record observedAnnouncement when you know the tested output, or observedAnnouncementTokens when exact phrasing is noisy but role/name/state tokens are clear. Tactual compares those against its modeled announcement for the matched target and reports missing or unexpected tokens. Use tactual calibration-report or MCP calibration_report to run a dataset against saved analyze-url --full-json output and emit scoringSignals. Use tactual observe-announcement to generate or append announcement-only observations from a saved analysis, or npm run -- nvda:vm:observe -- ... in this repo to organize a controlled NVDA VM capture folder. The repo's versioned corpus lives under calibration/corpus/; run npm run calibration:corpus to audit coverage gates and npm run calibration:matrix after npm run build to rank reachability tuning work by MAE, bias, variance, and stale sequence-plan drift.
Release readiness and known boundaries are documented in docs/RELEASE_TEST_MATRIX.md, docs/LIMITATIONS.md, and docs/NVDA_VM_OBSERVER.md.
Development
Security
Browser sandboxing
Tactual always runs Playwright with default Chromium sandboxing enabled. It never disables web security or modifies the browser's security model. All page interactions happen within the standard Chromium process sandbox.
Safe-action policy
When exploration is enabled (--explore), Tactual classifies interactive elements into three tiers before activating them:
This is a keyword-based heuristic — it cannot detect semantic deception (e.g., a "Save" button that actually deletes data) or inspect server-side behavior. For production use, always run exploration against trusted or sandboxed environments.
URL validation
All URLs are validated before navigation. The CLI accepts http:, https:, and file: schemes so local fixtures work; MCP URL-taking tools accept only http: and https: to avoid exposing local files through agent-controlled browser navigation. javascript:, data:, blob:, and vbscript: are rejected. URLs with embedded credentials (e.g. https://user:pass@host/) are also rejected. Private/internal IP ranges are not filtered — running Tactual in an environment with access to internal services is equivalent to letting any other Playwright-driven tool reach them, so treat the URL input as trusted input.
License
Apache-2.0
Attribution
The simulator's role/state phrasing is calibrated against the W3C ARIA-AT project, which is licensed under CC-BY 4.0. Tactual does not bundle ARIA-AT data; the calibration script (npm run calibrate) fetches assertions from the upstream repository at run time. If you publish Tactual calibration results, please attribute the W3C ARIA-AT project as the source of the ground-truth assertions.
ARIA role/attribute support data referenced in interop risk scoring is derived from a11ysupport.io and the same ARIA-AT project.
來源:README.md,提交 69d32e8
工具
0版本歷史
1- v0.2.1最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分