@weaaare/mcp-virtual-screen-reader-auditor 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/virtual-prompts.d.ts +6 -0
- package/dist/prompts/virtual-prompts.d.ts.map +1 -0
- package/dist/prompts/virtual-prompts.js +272 -0
- package/dist/prompts/virtual-prompts.js.map +1 -0
- package/dist/screen-readers/virtual/virtual.adapter.d.ts +32 -0
- package/dist/screen-readers/virtual/virtual.adapter.d.ts.map +1 -0
- package/dist/screen-readers/virtual/virtual.adapter.js +246 -0
- package/dist/screen-readers/virtual/virtual.adapter.js.map +1 -0
- package/dist/screen-readers/virtual/virtual.tools.d.ts +4 -0
- package/dist/screen-readers/virtual/virtual.tools.d.ts.map +1 -0
- package/dist/screen-readers/virtual/virtual.tools.js +297 -0
- package/dist/screen-readers/virtual/virtual.tools.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +48 -0
- package/dist/server.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @weaaare/mcp-virtual-screen-reader-auditor
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for **headless virtual screen reader accessibility audits**. Works on any OS — no native screen reader required. Launches a real browser, injects a virtual screen reader, and navigates the live accessibility tree including dynamic/SPA content.
|
|
4
|
+
|
|
5
|
+
Covers **WCAG 2.2** criteria using the same audit, findings, and reporting framework as `@weaaare/mcp-voiceover-auditor`.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `virtual_start` | Start the Virtual Screen Reader on a URL or raw HTML (launches headless browser) |
|
|
12
|
+
| `virtual_stop` | Stop the Virtual Screen Reader and release resources |
|
|
13
|
+
| `virtual_next` | Move cursor to the next item in the accessibility tree |
|
|
14
|
+
| `virtual_previous` | Move cursor to the previous item in the accessibility tree |
|
|
15
|
+
| `virtual_act` | Perform default action for the current item (e.g., activate a link/button) |
|
|
16
|
+
| `virtual_interact` | Interact with the current container item |
|
|
17
|
+
| `virtual_stop_interacting` | Stop interacting with the current container item |
|
|
18
|
+
| `virtual_press` | Press a key on the focused item (e.g. `Enter`, `Tab`, `ArrowDown`) |
|
|
19
|
+
| `virtual_type` | Type text into the currently focused item |
|
|
20
|
+
| `virtual_perform` | Semantic navigation by element type: headings, links, landmarks, forms, figures |
|
|
21
|
+
| `virtual_item_text` | Get text of the item under the Virtual Screen Reader cursor |
|
|
22
|
+
| `virtual_last_spoken_phrase` | Get the last phrase spoken by the Virtual Screen Reader |
|
|
23
|
+
| `virtual_spoken_phrase_log` | Get full spoken phrase history for this session |
|
|
24
|
+
| `virtual_item_text_log` | Get full visited item text history for this session |
|
|
25
|
+
| `virtual_clear_spoken_phrase_log` | Clear the spoken phrase log |
|
|
26
|
+
| `virtual_clear_item_text_log` | Clear the visited item text log |
|
|
27
|
+
| `virtual_click` | Click the mouse at the current position |
|
|
28
|
+
| `start_audit` | Start a structured audit session with metadata |
|
|
29
|
+
| `log_finding` | Log violations/warnings/passes with WCAG criteria and recommendations |
|
|
30
|
+
| `get_audit_status` | Get current audit progress and finding counters |
|
|
31
|
+
| `get_findings` | Retrieve findings from current or latest session |
|
|
32
|
+
| `end_audit` | End audit session and return summary data |
|
|
33
|
+
| `generate_report` | Generate reports in Markdown, JSON, or CSV |
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g @weaaare/mcp-virtual-screen-reader-auditor
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or use directly with `npx`:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx @weaaare/mcp-virtual-screen-reader-auditor
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
### VS Code (GitHub Copilot)
|
|
50
|
+
|
|
51
|
+
Add to `.vscode/mcp.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"servers": {
|
|
56
|
+
"virtual-screen-reader-auditor": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["-y", "@weaaare/mcp-virtual-screen-reader-auditor"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Claude Desktop
|
|
65
|
+
|
|
66
|
+
Add to `claude_desktop_config.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"virtual-screen-reader-auditor": {
|
|
72
|
+
"command": "npx",
|
|
73
|
+
"args": ["-y", "@weaaare/mcp-virtual-screen-reader-auditor"]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT - [weAAAre](https://weAAAre.com)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import { createServer } from './server.js';
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const server = createServer();
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
await server.connect(transport);
|
|
7
|
+
console.error('virtual-screen-reader-auditor MCP server running on stdio');
|
|
8
|
+
};
|
|
9
|
+
main().catch((error) => {
|
|
10
|
+
console.error('Fatal error:', error);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;IACrC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PromptDefinition } from '@weaaare/mcp-auditor-core';
|
|
2
|
+
import { getPromptMessages, listPrompts } from '@weaaare/mcp-auditor-core';
|
|
3
|
+
export declare const VIRTUAL_PROMPTS: ReadonlyMap<string, PromptDefinition>;
|
|
4
|
+
export declare const listVirtualPrompts: () => ReturnType<typeof listPrompts>;
|
|
5
|
+
export declare const getVirtualPromptMessages: (name: string, args: Record<string, string | undefined>) => ReturnType<typeof getPromptMessages>;
|
|
6
|
+
//# sourceMappingURL=virtual-prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-prompts.d.ts","sourceRoot":"","sources":["../../src/prompts/virtual-prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAyR3E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAMhE,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAAO,UAAU,CAAC,OAAO,WAAW,CACrC,CAAC;AAE/B,eAAO,MAAM,wBAAwB,GACnC,MAAM,MAAM,EACZ,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACvC,UAAU,CAAC,OAAO,iBAAiB,CAAmD,CAAC"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { getPromptMessages, listPrompts } from '@weaaare/mcp-auditor-core';
|
|
2
|
+
// ─── Virtual Screen Reader Prompts ───────────────────────────────────────────
|
|
3
|
+
// These use the virtual screen reader (headless browser + injected SR).
|
|
4
|
+
// Workflow: virtual_start → navigate → log_finding → virtual_stop → report
|
|
5
|
+
const virtualAccessibilityAudit = {
|
|
6
|
+
prompt: {
|
|
7
|
+
name: 'virtual_accessibility_audit',
|
|
8
|
+
description: 'Run an accessibility audit using the Virtual Screen Reader. Choose the page and the type of test. Works on any OS — no real screen reader required.',
|
|
9
|
+
arguments: [
|
|
10
|
+
{
|
|
11
|
+
name: 'url',
|
|
12
|
+
description: 'URL of the page to audit',
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'testType',
|
|
17
|
+
description: 'Type of test to run: full | headings | forms | navigation | links | images',
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'wcagLevel',
|
|
22
|
+
description: 'WCAG conformance level: A, AA, or AAA (default: AA)',
|
|
23
|
+
required: false,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
getMessage: (args) => {
|
|
28
|
+
const url = args.url ?? 'UNKNOWN_URL';
|
|
29
|
+
const testType = args.testType ?? 'full';
|
|
30
|
+
const wcagLevel = args.wcagLevel ?? 'AA';
|
|
31
|
+
const testBlocks = {
|
|
32
|
+
full: `## Phase 2 — Audit Workflow
|
|
33
|
+
|
|
34
|
+
### 2.1 Page Title & Language
|
|
35
|
+
- \`virtual_item_text\` — check what the screen reader announces on page load
|
|
36
|
+
- Verify the page title is descriptive (WCAG 2.4.2)
|
|
37
|
+
- \`log_finding\`
|
|
38
|
+
|
|
39
|
+
### 2.2 Landmark Regions
|
|
40
|
+
- \`virtual_perform\` → moveToNextLandmark (repeat until exhausted) to get overview
|
|
41
|
+
- Then check specific landmark types directly:
|
|
42
|
+
- \`virtual_perform\` → moveToNextMain (required — verify it exists)
|
|
43
|
+
- \`virtual_perform\` → moveToNextNavigation (recommended)
|
|
44
|
+
- \`virtual_perform\` → moveToNextBanner (header)
|
|
45
|
+
- \`virtual_perform\` → moveToNextContentinfo (footer)
|
|
46
|
+
- \`virtual_perform\` → moveToNextComplementary (aside)
|
|
47
|
+
- \`virtual_perform\` → moveToNextSearch (search region)
|
|
48
|
+
- \`log_finding\` for WCAG 1.3.1
|
|
49
|
+
|
|
50
|
+
### 2.3 Heading Structure
|
|
51
|
+
- \`virtual_perform\` → moveToNextHeading (repeat until exhausted)
|
|
52
|
+
- Record each heading level and text via \`virtual_last_spoken_phrase\` and \`virtual_item_text\`
|
|
53
|
+
- Verify: exactly one h1, no skipped levels
|
|
54
|
+
- \`log_finding\` for WCAG 1.3.1, 2.4.6
|
|
55
|
+
|
|
56
|
+
### 2.4 Links
|
|
57
|
+
- \`virtual_perform\` → moveToNextLink (repeat)
|
|
58
|
+
- Verify descriptive link text (not "click here", "read more", "here")
|
|
59
|
+
- \`log_finding\` for WCAG 2.4.4
|
|
60
|
+
|
|
61
|
+
### 2.5 Forms
|
|
62
|
+
- \`virtual_perform\` → moveToNextForm (repeat) — find form containers
|
|
63
|
+
- Within each form: \`virtual_perform\` → findNextControl (repeat) — find individual controls
|
|
64
|
+
- For each control: \`virtual_last_spoken_phrase\` to verify label, required state
|
|
65
|
+
- \`log_finding\` for WCAG 1.3.1, 3.3.2, 4.1.2
|
|
66
|
+
|
|
67
|
+
### 2.6 Images
|
|
68
|
+
- \`virtual_perform\` → moveToNextFigure (repeat until exhausted) — jump directly from image to image
|
|
69
|
+
- For each image:
|
|
70
|
+
a. \`virtual_last_spoken_phrase\` — check what is announced
|
|
71
|
+
b. \`virtual_item_text\` — check the text content
|
|
72
|
+
c. Informative images: verify alt text exists and is descriptive
|
|
73
|
+
d. Decorative images: verify they are hidden (role="presentation" or alt="")
|
|
74
|
+
- \`log_finding\` for WCAG 1.1.1
|
|
75
|
+
|
|
76
|
+
### 2.7 Keyboard Navigation
|
|
77
|
+
- Use \`virtual_press\` with "Tab" to tab through the page
|
|
78
|
+
- Verify logical focus order, no keyboard traps, interactive elements reachable
|
|
79
|
+
- \`log_finding\` for WCAG 2.1.1, 2.1.2, 2.4.3`,
|
|
80
|
+
headings: `## Phase 2 — Heading Audit
|
|
81
|
+
|
|
82
|
+
- \`virtual_perform\` → moveToNextHeading (repeat until exhausted) — collect all headings
|
|
83
|
+
- For each heading record: level and text via \`virtual_last_spoken_phrase\` and \`virtual_item_text\`
|
|
84
|
+
- Then verify h1 count with a targeted pass:
|
|
85
|
+
- \`virtual_perform\` → moveToNextHeadingLevel1 (repeat) — count all h1s (must be exactly one)
|
|
86
|
+
- If skipped levels suspected, verify with level-specific commands:
|
|
87
|
+
- moveToNextHeadingLevel2, moveToNextHeadingLevel3, etc.
|
|
88
|
+
- Verify:
|
|
89
|
+
- Exactly one h1 on the page
|
|
90
|
+
- No skipped levels (h1→h2→h3, not h1→h3)
|
|
91
|
+
- Headings are descriptive (not empty, not just "Section")
|
|
92
|
+
- Heading hierarchy reflects content structure
|
|
93
|
+
- \`log_finding\` for WCAG 1.3.1, 2.4.6`,
|
|
94
|
+
forms: `## Phase 2 — Form Audit
|
|
95
|
+
|
|
96
|
+
- \`virtual_perform\` → moveToNextForm (repeat) — find form containers
|
|
97
|
+
- Within each form, find individual controls:
|
|
98
|
+
a. \`virtual_perform\` → findNextControl (repeat until exhausted)
|
|
99
|
+
- For each control:
|
|
100
|
+
a. Record announcement via \`virtual_last_spoken_phrase\`
|
|
101
|
+
b. \`virtual_item_text\` — verify label association
|
|
102
|
+
c. Check required state is announced
|
|
103
|
+
d. For text inputs: \`virtual_type\` to enter text, check validation
|
|
104
|
+
e. \`virtual_press\` with "Tab" to verify keyboard flow
|
|
105
|
+
- Also check ARIA error relationships: \`virtual_perform\` → jumpToErrorMessageElement
|
|
106
|
+
- Verify:
|
|
107
|
+
- All inputs have labels (WCAG 1.3.1, 3.3.2)
|
|
108
|
+
- Required fields indicated (WCAG 3.3.2)
|
|
109
|
+
- Error messages announced (WCAG 3.3.1)
|
|
110
|
+
- Form completable entirely by keyboard (WCAG 2.1.1)
|
|
111
|
+
- Submit button reachable by keyboard
|
|
112
|
+
- \`log_finding\` for each issue`,
|
|
113
|
+
navigation: `## Phase 2 — Navigation Audit
|
|
114
|
+
|
|
115
|
+
### Skip Links
|
|
116
|
+
- \`virtual_press\` with "Tab" once from start — check for a "skip to content" link
|
|
117
|
+
|
|
118
|
+
### Landmarks
|
|
119
|
+
- Check each specific landmark type directly for precise verification:
|
|
120
|
+
- \`virtual_perform\` → moveToNextMain — MUST exist (required landmark)
|
|
121
|
+
- \`virtual_perform\` → moveToNextNavigation — recommended
|
|
122
|
+
- \`virtual_perform\` → moveToNextBanner — header region
|
|
123
|
+
- \`virtual_perform\` → moveToNextContentinfo — footer region
|
|
124
|
+
- \`virtual_perform\` → moveToNextComplementary — aside region
|
|
125
|
+
- \`virtual_perform\` → moveToNextSearch — search region
|
|
126
|
+
- \`virtual_perform\` → moveToNextRegion — named regions
|
|
127
|
+
- Then \`virtual_perform\` → moveToNextLandmark (repeat) to catch any additional landmarks
|
|
128
|
+
- \`log_finding\` for WCAG 1.3.1
|
|
129
|
+
|
|
130
|
+
### Tab Order
|
|
131
|
+
- \`virtual_press\` with "Tab" through entire page
|
|
132
|
+
- Verify order follows visual/logical reading order
|
|
133
|
+
- Verify no keyboard traps (can always Tab out)
|
|
134
|
+
- Verify all interactive elements are reachable
|
|
135
|
+
- \`log_finding\` for WCAG 2.1.1, 2.1.2, 2.4.3
|
|
136
|
+
|
|
137
|
+
### Focus Management
|
|
138
|
+
- Check modals: focus should be trapped inside
|
|
139
|
+
- Check expandable sections: focus should move appropriately
|
|
140
|
+
- \`log_finding\` for WCAG 2.4.3`,
|
|
141
|
+
links: `## Phase 2 — Link Audit
|
|
142
|
+
|
|
143
|
+
- \`virtual_perform\` → moveToNextLink (repeat until exhausted)
|
|
144
|
+
- For each link:
|
|
145
|
+
a. \`virtual_last_spoken_phrase\` — record full announcement
|
|
146
|
+
b. \`virtual_item_text\` — record link text
|
|
147
|
+
c. Verify link text is descriptive (not "click here", "read more", "here", "link")
|
|
148
|
+
d. Verify link purpose is clear from text alone or surrounding context
|
|
149
|
+
e. Check for redundant links (same destination, different text)
|
|
150
|
+
- \`log_finding\` for WCAG 2.4.4 (Link Purpose in Context)`,
|
|
151
|
+
images: `## Phase 2 — Image Audit
|
|
152
|
+
|
|
153
|
+
- \`virtual_perform\` → moveToNextFigure (repeat until exhausted) — jump directly from image to image
|
|
154
|
+
- For each image:
|
|
155
|
+
a. \`virtual_last_spoken_phrase\` — check what the screen reader announces
|
|
156
|
+
b. \`virtual_item_text\` — check the text content
|
|
157
|
+
c. Informative images: verify alt text exists and is descriptive
|
|
158
|
+
d. Decorative images: verify they are hidden from the screen reader (role="presentation" or alt="")
|
|
159
|
+
e. Complex images (charts, diagrams): verify long description is provided (check with \`virtual_perform\` → jumpToDetailsElement)
|
|
160
|
+
- \`log_finding\` for WCAG 1.1.1 (Non-text Content)`,
|
|
161
|
+
};
|
|
162
|
+
const testBlock = testBlocks[testType] ?? testBlocks.full;
|
|
163
|
+
return [
|
|
164
|
+
{
|
|
165
|
+
role: 'user',
|
|
166
|
+
content: {
|
|
167
|
+
type: 'text',
|
|
168
|
+
text: `Run a ${testType} accessibility audit of ${url} using the Virtual Screen Reader. Follow every step in order.
|
|
169
|
+
|
|
170
|
+
## Phase 1 — Start
|
|
171
|
+
1. \`virtual_start\` with url "${url}"
|
|
172
|
+
2. \`start_audit\` with url "${url}", screenReader "virtual", wcagLevel "${wcagLevel}"
|
|
173
|
+
|
|
174
|
+
${testBlock}
|
|
175
|
+
|
|
176
|
+
## Handling Issues
|
|
177
|
+
- Inability to navigate to an element via screen reader IS a finding — log it as a violation
|
|
178
|
+
- Try a workaround (e.g., Tab key via \`virtual_press\`) and continue; never stop at the first failure
|
|
179
|
+
|
|
180
|
+
## Phase 3 — Report & Shutdown
|
|
181
|
+
1. \`end_audit\`
|
|
182
|
+
2. \`generate_report\` with format "markdown"
|
|
183
|
+
3. Present the report with critical issues first
|
|
184
|
+
4. \`virtual_stop\``,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
const virtualFullAudit = {
|
|
191
|
+
prompt: {
|
|
192
|
+
name: 'virtual_full_audit',
|
|
193
|
+
description: 'Comprehensive virtual screen reader audit. Covers headings, landmarks, links, forms, images, and keyboard navigation.',
|
|
194
|
+
arguments: [
|
|
195
|
+
{
|
|
196
|
+
name: 'url',
|
|
197
|
+
description: 'URL of the page to audit',
|
|
198
|
+
required: true,
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: 'wcagLevel',
|
|
202
|
+
description: 'WCAG conformance level: A, AA, or AAA (default: AA)',
|
|
203
|
+
required: false,
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
getMessage: (args) => virtualAccessibilityAudit.getMessage({
|
|
208
|
+
...args,
|
|
209
|
+
testType: 'full',
|
|
210
|
+
}),
|
|
211
|
+
};
|
|
212
|
+
const virtualHeadingAudit = {
|
|
213
|
+
prompt: {
|
|
214
|
+
name: 'virtual_heading_audit',
|
|
215
|
+
description: 'Audit heading structure using the Virtual Screen Reader. Checks h1 uniqueness, hierarchy, and descriptive content.',
|
|
216
|
+
arguments: [
|
|
217
|
+
{
|
|
218
|
+
name: 'url',
|
|
219
|
+
description: 'URL of the page to audit',
|
|
220
|
+
required: true,
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
getMessage: (args) => virtualAccessibilityAudit.getMessage({
|
|
225
|
+
...args,
|
|
226
|
+
testType: 'headings',
|
|
227
|
+
}),
|
|
228
|
+
};
|
|
229
|
+
const virtualFormAudit = {
|
|
230
|
+
prompt: {
|
|
231
|
+
name: 'virtual_form_audit',
|
|
232
|
+
description: 'Audit form accessibility using the Virtual Screen Reader: labels, error messages, required fields, and keyboard navigation.',
|
|
233
|
+
arguments: [
|
|
234
|
+
{
|
|
235
|
+
name: 'url',
|
|
236
|
+
description: 'URL of the page with forms to audit',
|
|
237
|
+
required: true,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
getMessage: (args) => virtualAccessibilityAudit.getMessage({
|
|
242
|
+
...args,
|
|
243
|
+
testType: 'forms',
|
|
244
|
+
}),
|
|
245
|
+
};
|
|
246
|
+
const virtualNavigationAudit = {
|
|
247
|
+
prompt: {
|
|
248
|
+
name: 'virtual_navigation_audit',
|
|
249
|
+
description: 'Audit keyboard navigation and landmarks using the Virtual Screen Reader. Checks tab order, landmarks, skip links, and focus management.',
|
|
250
|
+
arguments: [
|
|
251
|
+
{
|
|
252
|
+
name: 'url',
|
|
253
|
+
description: 'URL of the page to audit',
|
|
254
|
+
required: true,
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
getMessage: (args) => virtualAccessibilityAudit.getMessage({
|
|
259
|
+
...args,
|
|
260
|
+
testType: 'navigation',
|
|
261
|
+
}),
|
|
262
|
+
};
|
|
263
|
+
export const VIRTUAL_PROMPTS = new Map([
|
|
264
|
+
['virtual_accessibility_audit', virtualAccessibilityAudit],
|
|
265
|
+
['virtual_full_audit', virtualFullAudit],
|
|
266
|
+
['virtual_heading_audit', virtualHeadingAudit],
|
|
267
|
+
['virtual_form_audit', virtualFormAudit],
|
|
268
|
+
['virtual_navigation_audit', virtualNavigationAudit],
|
|
269
|
+
]);
|
|
270
|
+
export const listVirtualPrompts = () => listPrompts(VIRTUAL_PROMPTS);
|
|
271
|
+
export const getVirtualPromptMessages = (name, args) => getPromptMessages(name, args, VIRTUAL_PROMPTS);
|
|
272
|
+
//# sourceMappingURL=virtual-prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-prompts.js","sourceRoot":"","sources":["../../src/prompts/virtual-prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ClickOptions, ScreenReaderCommandResult, ScreenReaderPort } from '@weaaare/mcp-auditor-core';
|
|
2
|
+
export declare class VirtualScreenReaderAdapter implements ScreenReaderPort {
|
|
3
|
+
private browser;
|
|
4
|
+
private context;
|
|
5
|
+
private page;
|
|
6
|
+
private getPage;
|
|
7
|
+
private ensureBrowser;
|
|
8
|
+
loadUrl(url: string): Promise<void>;
|
|
9
|
+
loadHtml(html: string): Promise<void>;
|
|
10
|
+
start(): Promise<ScreenReaderCommandResult>;
|
|
11
|
+
stop(): Promise<ScreenReaderCommandResult>;
|
|
12
|
+
next(): Promise<ScreenReaderCommandResult>;
|
|
13
|
+
previous(): Promise<ScreenReaderCommandResult>;
|
|
14
|
+
act(): Promise<ScreenReaderCommandResult>;
|
|
15
|
+
interact(): Promise<ScreenReaderCommandResult>;
|
|
16
|
+
stopInteracting(): Promise<ScreenReaderCommandResult>;
|
|
17
|
+
press(key: string): Promise<ScreenReaderCommandResult>;
|
|
18
|
+
type(text: string): Promise<ScreenReaderCommandResult>;
|
|
19
|
+
perform(command: string): Promise<ScreenReaderCommandResult>;
|
|
20
|
+
performCommander(_command: string): Promise<ScreenReaderCommandResult>;
|
|
21
|
+
getCommanderCommands(): string[];
|
|
22
|
+
itemText(): Promise<string>;
|
|
23
|
+
lastSpokenPhrase(): Promise<string>;
|
|
24
|
+
spokenPhraseLog(): Promise<string[]>;
|
|
25
|
+
itemTextLog(): Promise<string[]>;
|
|
26
|
+
clearSpokenPhraseLog(): Promise<void>;
|
|
27
|
+
clearItemTextLog(): Promise<void>;
|
|
28
|
+
click(options?: ClickOptions): Promise<ScreenReaderCommandResult>;
|
|
29
|
+
detect(): Promise<boolean>;
|
|
30
|
+
isDefault(): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=virtual.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual.adapter.d.ts","sourceRoot":"","sources":["../../../src/screen-readers/virtual/virtual.adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAqBnC,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IAEjC,OAAO,CAAC,OAAO;YASD,aAAa;IA6BrB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAU3C,IAAI,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAoC1C,IAAI,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAY1C,QAAQ,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAY9C,GAAG,IAAI,OAAO,CAAC,yBAAyB,CAAC;IASzC,QAAQ,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAQ9C,eAAe,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAQrD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAStD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAQtD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAmBlE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAMtE,oBAAoB,IAAI,MAAM,EAAE;IAI1B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAO3B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAOnC,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAOpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAOhC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAajE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAI1B,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAGpC"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { chromium } from 'playwright-core';
|
|
5
|
+
const _require = createRequire(import.meta.url);
|
|
6
|
+
const BROWSER_BUNDLE_PATH = join(dirname(_require.resolve('@guidepup/virtual-screen-reader/package.json')), 'lib', 'esm', 'index.browser.js');
|
|
7
|
+
const BUNDLE_INTERCEPT_URL = 'https://virtual-sr-local/bundle.js';
|
|
8
|
+
const ADAPT_VIRTUAL_COMMANDS = {
|
|
9
|
+
findNextHeading: 'moveToNextHeading',
|
|
10
|
+
findPreviousHeading: 'moveToPreviousHeading',
|
|
11
|
+
findNextLink: 'moveToNextLink',
|
|
12
|
+
findPreviousLink: 'moveToPreviousLink',
|
|
13
|
+
findNextControl: 'moveToNextForm',
|
|
14
|
+
findPreviousControl: 'moveToPreviousForm',
|
|
15
|
+
};
|
|
16
|
+
export class VirtualScreenReaderAdapter {
|
|
17
|
+
browser = null;
|
|
18
|
+
context = null;
|
|
19
|
+
page = null;
|
|
20
|
+
getPage() {
|
|
21
|
+
if (!this.page) {
|
|
22
|
+
throw new Error('No page loaded. Call loadUrl() or loadHtml() before using the virtual screen reader.');
|
|
23
|
+
}
|
|
24
|
+
return this.page;
|
|
25
|
+
}
|
|
26
|
+
async ensureBrowser() {
|
|
27
|
+
if (this.page) {
|
|
28
|
+
try {
|
|
29
|
+
await this.page.close();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* ignore */
|
|
33
|
+
}
|
|
34
|
+
this.page = null;
|
|
35
|
+
}
|
|
36
|
+
if (this.context) {
|
|
37
|
+
try {
|
|
38
|
+
await this.context.close();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
/* ignore */
|
|
42
|
+
}
|
|
43
|
+
this.context = null;
|
|
44
|
+
}
|
|
45
|
+
if (!this.browser) {
|
|
46
|
+
this.browser = await chromium.launch({ headless: true, channel: 'chrome' });
|
|
47
|
+
}
|
|
48
|
+
this.context = await this.browser.newContext({ bypassCSP: true });
|
|
49
|
+
this.page = await this.context.newPage();
|
|
50
|
+
const bundleSource = readFileSync(BROWSER_BUNDLE_PATH, 'utf-8');
|
|
51
|
+
await this.page.route(BUNDLE_INTERCEPT_URL, (route) => {
|
|
52
|
+
route.fulfill({ contentType: 'application/javascript', body: bundleSource });
|
|
53
|
+
});
|
|
54
|
+
return this.page;
|
|
55
|
+
}
|
|
56
|
+
async loadUrl(url) {
|
|
57
|
+
const page = await this.ensureBrowser();
|
|
58
|
+
await page.goto(url, { waitUntil: 'load' });
|
|
59
|
+
}
|
|
60
|
+
async loadHtml(html) {
|
|
61
|
+
const page = await this.ensureBrowser();
|
|
62
|
+
await page.setContent(html, { waitUntil: 'load' });
|
|
63
|
+
}
|
|
64
|
+
async start() {
|
|
65
|
+
const page = this.getPage();
|
|
66
|
+
await page.evaluate(async (bundleUrl) => {
|
|
67
|
+
const { virtual } = await import(bundleUrl);
|
|
68
|
+
globalThis.__guidepupVirtual = virtual;
|
|
69
|
+
await virtual.start({ container: globalThis.document.body });
|
|
70
|
+
}, BUNDLE_INTERCEPT_URL);
|
|
71
|
+
return { action: 'Virtual Screen Reader started successfully' };
|
|
72
|
+
}
|
|
73
|
+
async stop() {
|
|
74
|
+
if (this.page) {
|
|
75
|
+
try {
|
|
76
|
+
await this.page.evaluate(async () => {
|
|
77
|
+
const v = globalThis.__guidepupVirtual;
|
|
78
|
+
if (v)
|
|
79
|
+
await v.stop();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* page may already be closed */
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await this.page.close();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* ignore */
|
|
90
|
+
}
|
|
91
|
+
this.page = null;
|
|
92
|
+
}
|
|
93
|
+
if (this.context) {
|
|
94
|
+
try {
|
|
95
|
+
await this.context.close();
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
/* ignore */
|
|
99
|
+
}
|
|
100
|
+
this.context = null;
|
|
101
|
+
}
|
|
102
|
+
if (this.browser) {
|
|
103
|
+
try {
|
|
104
|
+
await this.browser.close();
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
/* ignore */
|
|
108
|
+
}
|
|
109
|
+
this.browser = null;
|
|
110
|
+
}
|
|
111
|
+
return { action: 'Virtual Screen Reader stopped successfully' };
|
|
112
|
+
}
|
|
113
|
+
async next() {
|
|
114
|
+
const data = await this.getPage().evaluate(async () => {
|
|
115
|
+
const v = globalThis.__guidepupVirtual;
|
|
116
|
+
await v.next();
|
|
117
|
+
return {
|
|
118
|
+
itemText: (await v.itemText()),
|
|
119
|
+
spokenPhrase: (await v.lastSpokenPhrase()),
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
return { action: 'moved to next item', ...data };
|
|
123
|
+
}
|
|
124
|
+
async previous() {
|
|
125
|
+
const data = await this.getPage().evaluate(async () => {
|
|
126
|
+
const v = globalThis.__guidepupVirtual;
|
|
127
|
+
await v.previous();
|
|
128
|
+
return {
|
|
129
|
+
itemText: (await v.itemText()),
|
|
130
|
+
spokenPhrase: (await v.lastSpokenPhrase()),
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
return { action: 'moved to previous item', ...data };
|
|
134
|
+
}
|
|
135
|
+
async act() {
|
|
136
|
+
const data = await this.getPage().evaluate(async () => {
|
|
137
|
+
const v = globalThis.__guidepupVirtual;
|
|
138
|
+
await v.act();
|
|
139
|
+
return { spokenPhrase: (await v.lastSpokenPhrase()) };
|
|
140
|
+
});
|
|
141
|
+
return { action: 'performed default action', ...data };
|
|
142
|
+
}
|
|
143
|
+
async interact() {
|
|
144
|
+
await this.getPage().evaluate(async () => {
|
|
145
|
+
const v = globalThis.__guidepupVirtual;
|
|
146
|
+
await v.interact();
|
|
147
|
+
});
|
|
148
|
+
return { action: 'interact (no-op in virtual screen reader)' };
|
|
149
|
+
}
|
|
150
|
+
async stopInteracting() {
|
|
151
|
+
await this.getPage().evaluate(async () => {
|
|
152
|
+
const v = globalThis.__guidepupVirtual;
|
|
153
|
+
await v.stopInteracting();
|
|
154
|
+
});
|
|
155
|
+
return { action: 'stop interacting (no-op in virtual screen reader)' };
|
|
156
|
+
}
|
|
157
|
+
async press(key) {
|
|
158
|
+
const data = await this.getPage().evaluate(async (k) => {
|
|
159
|
+
const v = globalThis.__guidepupVirtual;
|
|
160
|
+
await v.press(k);
|
|
161
|
+
return { spokenPhrase: (await v.lastSpokenPhrase()) };
|
|
162
|
+
}, key);
|
|
163
|
+
return { action: `pressed key: ${key}`, ...data };
|
|
164
|
+
}
|
|
165
|
+
async type(text) {
|
|
166
|
+
await this.getPage().evaluate(async (t) => {
|
|
167
|
+
const v = globalThis.__guidepupVirtual;
|
|
168
|
+
await v.type(t);
|
|
169
|
+
}, text);
|
|
170
|
+
return { action: `typed: ${text}` };
|
|
171
|
+
}
|
|
172
|
+
async perform(command) {
|
|
173
|
+
const virtualCommand = ADAPT_VIRTUAL_COMMANDS[command] ?? command;
|
|
174
|
+
const data = await this.getPage().evaluate(async (cmd) => {
|
|
175
|
+
const v = globalThis.__guidepupVirtual;
|
|
176
|
+
const cmdValue = v.commands[cmd];
|
|
177
|
+
if (!cmdValue) {
|
|
178
|
+
throw new Error(`Unknown command: ${cmd}. Available: ${Object.keys(v.commands).join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
await v.perform(cmdValue);
|
|
181
|
+
return {
|
|
182
|
+
itemText: (await v.itemText()),
|
|
183
|
+
spokenPhrase: (await v.lastSpokenPhrase()),
|
|
184
|
+
};
|
|
185
|
+
}, virtualCommand);
|
|
186
|
+
return { action: `performed command: ${command}`, ...data };
|
|
187
|
+
}
|
|
188
|
+
performCommander(_command) {
|
|
189
|
+
throw new Error('Commander commands are not supported in Virtual Screen Reader. Use perform() with virtual navigation commands instead (e.g., moveToNextLandmark, moveToNextHeadingLevel1).');
|
|
190
|
+
}
|
|
191
|
+
getCommanderCommands() {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
async itemText() {
|
|
195
|
+
return this.getPage().evaluate(async () => {
|
|
196
|
+
const v = globalThis.__guidepupVirtual;
|
|
197
|
+
return (await v.itemText());
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async lastSpokenPhrase() {
|
|
201
|
+
return this.getPage().evaluate(async () => {
|
|
202
|
+
const v = globalThis.__guidepupVirtual;
|
|
203
|
+
return (await v.lastSpokenPhrase());
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async spokenPhraseLog() {
|
|
207
|
+
return this.getPage().evaluate(async () => {
|
|
208
|
+
const v = globalThis.__guidepupVirtual;
|
|
209
|
+
return (await v.spokenPhraseLog());
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async itemTextLog() {
|
|
213
|
+
return this.getPage().evaluate(async () => {
|
|
214
|
+
const v = globalThis.__guidepupVirtual;
|
|
215
|
+
return (await v.itemTextLog());
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async clearSpokenPhraseLog() {
|
|
219
|
+
await this.getPage().evaluate(async () => {
|
|
220
|
+
const v = globalThis.__guidepupVirtual;
|
|
221
|
+
await v.clearSpokenPhraseLog();
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async clearItemTextLog() {
|
|
225
|
+
await this.getPage().evaluate(async () => {
|
|
226
|
+
const v = globalThis.__guidepupVirtual;
|
|
227
|
+
await v.clearItemTextLog();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async click(options) {
|
|
231
|
+
const button = options?.button ?? 'left';
|
|
232
|
+
const clickCount = options?.clickCount ?? 1;
|
|
233
|
+
await this.getPage().evaluate(async (opts) => {
|
|
234
|
+
const v = globalThis.__guidepupVirtual;
|
|
235
|
+
await v.click({ button: opts.button, clickCount: opts.clickCount });
|
|
236
|
+
}, { button, clickCount });
|
|
237
|
+
return { action: 'clicked mouse', spokenPhrase: `${button} click x${clickCount}` };
|
|
238
|
+
}
|
|
239
|
+
async detect() {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
async isDefault() {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=virtual.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual.adapter.js","sourceRoot":"","sources":["../../../src/screen-readers/virtual/virtual.adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ToolModule } from '@weaaare/mcp-auditor-core';
|
|
2
|
+
import type { VirtualScreenReaderAdapter } from './virtual.adapter.js';
|
|
3
|
+
export declare const createVirtualTools: (adapter: VirtualScreenReaderAdapter) => ToolModule;
|
|
4
|
+
//# sourceMappingURL=virtual.tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual.tools.d.ts","sourceRoot":"","sources":["../../../src/screen-readers/virtual/virtual.tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAqTvE,eAAO,MAAM,kBAAkB,GAAI,SAAS,0BAA0B,KAAG,UAGvE,CAAC"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { result } from '@weaaare/mcp-auditor-core';
|
|
2
|
+
const PERFORM_COMMAND_NAMES = [
|
|
3
|
+
'findNextHeading',
|
|
4
|
+
'findPreviousHeading',
|
|
5
|
+
'findNextLink',
|
|
6
|
+
'findPreviousLink',
|
|
7
|
+
'findNextControl',
|
|
8
|
+
'findPreviousControl',
|
|
9
|
+
'moveToNextHeading',
|
|
10
|
+
'moveToPreviousHeading',
|
|
11
|
+
'moveToNextHeadingLevel1',
|
|
12
|
+
'moveToPreviousHeadingLevel1',
|
|
13
|
+
'moveToNextHeadingLevel2',
|
|
14
|
+
'moveToPreviousHeadingLevel2',
|
|
15
|
+
'moveToNextHeadingLevel3',
|
|
16
|
+
'moveToPreviousHeadingLevel3',
|
|
17
|
+
'moveToNextHeadingLevel4',
|
|
18
|
+
'moveToPreviousHeadingLevel4',
|
|
19
|
+
'moveToNextHeadingLevel5',
|
|
20
|
+
'moveToPreviousHeadingLevel5',
|
|
21
|
+
'moveToNextHeadingLevel6',
|
|
22
|
+
'moveToPreviousHeadingLevel6',
|
|
23
|
+
'moveToNextLink',
|
|
24
|
+
'moveToPreviousLink',
|
|
25
|
+
'moveToNextLandmark',
|
|
26
|
+
'moveToPreviousLandmark',
|
|
27
|
+
'moveToNextBanner',
|
|
28
|
+
'moveToPreviousBanner',
|
|
29
|
+
'moveToNextNavigation',
|
|
30
|
+
'moveToPreviousNavigation',
|
|
31
|
+
'moveToNextMain',
|
|
32
|
+
'moveToPreviousMain',
|
|
33
|
+
'moveToNextRegion',
|
|
34
|
+
'moveToPreviousRegion',
|
|
35
|
+
'moveToNextContentinfo',
|
|
36
|
+
'moveToPreviousContentinfo',
|
|
37
|
+
'moveToNextComplementary',
|
|
38
|
+
'moveToPreviousComplementary',
|
|
39
|
+
'moveToNextSearch',
|
|
40
|
+
'moveToPreviousSearch',
|
|
41
|
+
'moveToNextForm',
|
|
42
|
+
'moveToPreviousForm',
|
|
43
|
+
'moveToNextFigure',
|
|
44
|
+
'moveToPreviousFigure',
|
|
45
|
+
'jumpToControlledElement',
|
|
46
|
+
'jumpToDetailsElement',
|
|
47
|
+
'jumpToErrorMessageElement',
|
|
48
|
+
];
|
|
49
|
+
const defineTools = () => [
|
|
50
|
+
{
|
|
51
|
+
name: 'virtual_start',
|
|
52
|
+
description: [
|
|
53
|
+
'Start the Virtual Screen Reader on a live web page or provided HTML content.',
|
|
54
|
+
'This launches a real browser (headless), navigates to the URL or loads the HTML,',
|
|
55
|
+
'and injects a virtual screen reader that navigates the live accessibility tree.',
|
|
56
|
+
'JavaScript on the page executes normally, so SPAs and dynamic content work.',
|
|
57
|
+
'',
|
|
58
|
+
"Provide either 'url' (preferred) or 'html'. If both are given, 'url' takes priority.",
|
|
59
|
+
'',
|
|
60
|
+
'Typical workflow:',
|
|
61
|
+
'1. Call virtual_start with the URL to audit',
|
|
62
|
+
'2. Navigate with virtual_next, virtual_previous, virtual_perform, etc.',
|
|
63
|
+
'3. Call virtual_stop when done',
|
|
64
|
+
].join('\n'),
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: 'object',
|
|
67
|
+
properties: {
|
|
68
|
+
url: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
description: 'URL to audit. A real browser navigates to this URL, so JS executes and dynamic content renders.',
|
|
71
|
+
},
|
|
72
|
+
html: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description: 'Raw HTML content to audit. Used as fallback when no URL is provided.',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'virtual_stop',
|
|
81
|
+
description: 'Stop the Virtual Screen Reader and release resources.',
|
|
82
|
+
inputSchema: { type: 'object', properties: {} },
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'virtual_next',
|
|
86
|
+
description: 'Move the Virtual Screen Reader cursor to the next item in the accessibility tree.',
|
|
87
|
+
inputSchema: { type: 'object', properties: {} },
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'virtual_previous',
|
|
91
|
+
description: 'Move the Virtual Screen Reader cursor to the previous item in the accessibility tree.',
|
|
92
|
+
inputSchema: { type: 'object', properties: {} },
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'virtual_act',
|
|
96
|
+
description: 'Perform the default action for the current item (e.g., activate a link or button).',
|
|
97
|
+
inputSchema: { type: 'object', properties: {} },
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'virtual_interact',
|
|
101
|
+
description: 'Interact with the current item. Note: this is a no-op in the Virtual Screen Reader.',
|
|
102
|
+
inputSchema: { type: 'object', properties: {} },
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'virtual_stop_interacting',
|
|
106
|
+
description: 'Stop interacting with the current item. Note: this is a no-op in the Virtual Screen Reader.',
|
|
107
|
+
inputSchema: { type: 'object', properties: {} },
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'virtual_press',
|
|
111
|
+
description: "Press a key on the focused item (e.g., 'Enter', 'Tab', 'ArrowDown', 'Command+f').",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
key: {
|
|
116
|
+
type: 'string',
|
|
117
|
+
description: "Key to press (e.g., 'Enter', 'Tab', 'ArrowDown', 'Shift+Tab')",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
required: ['key'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'virtual_type',
|
|
125
|
+
description: 'Type text into the focused item.',
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
properties: { text: { type: 'string', description: 'Text to type' } },
|
|
129
|
+
required: ['text'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'virtual_perform',
|
|
134
|
+
description: [
|
|
135
|
+
'Perform a navigation command in the Virtual Screen Reader.',
|
|
136
|
+
'Supports semantic navigation by element type: headings (by level), links, landmarks, forms, figures, and ARIA relationships.',
|
|
137
|
+
'',
|
|
138
|
+
'Common compatible commands: findNextHeading, findPreviousHeading, findNextLink, findPreviousLink, findNextControl, findPreviousControl.',
|
|
139
|
+
'',
|
|
140
|
+
'Virtual-specific commands: moveToNextHeadingLevel1-6, moveToNextLandmark, moveToNextBanner, moveToNextNavigation, moveToNextMain, moveToNextRegion, etc.',
|
|
141
|
+
].join('\n'),
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
command: {
|
|
146
|
+
type: 'string',
|
|
147
|
+
enum: [...PERFORM_COMMAND_NAMES],
|
|
148
|
+
description: 'Navigation command to perform',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
required: ['command'],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'virtual_item_text',
|
|
156
|
+
description: 'Get the text of the item currently under the Virtual Screen Reader cursor.',
|
|
157
|
+
inputSchema: { type: 'object', properties: {} },
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'virtual_last_spoken_phrase',
|
|
161
|
+
description: 'Get the last phrase spoken by the Virtual Screen Reader.',
|
|
162
|
+
inputSchema: { type: 'object', properties: {} },
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'virtual_spoken_phrase_log',
|
|
166
|
+
description: 'Get the log of all spoken phrases for this Virtual Screen Reader session.',
|
|
167
|
+
inputSchema: { type: 'object', properties: {} },
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'virtual_item_text_log',
|
|
171
|
+
description: 'Get the log of all visited item text for this Virtual Screen Reader session.',
|
|
172
|
+
inputSchema: { type: 'object', properties: {} },
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'virtual_clear_spoken_phrase_log',
|
|
176
|
+
description: 'Clear the log of all spoken phrases.',
|
|
177
|
+
inputSchema: { type: 'object', properties: {} },
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: 'virtual_clear_item_text_log',
|
|
181
|
+
description: 'Clear the log of all visited item text.',
|
|
182
|
+
inputSchema: { type: 'object', properties: {} },
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'virtual_click',
|
|
186
|
+
description: 'Click the mouse at the current position.',
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
button: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
enum: ['left', 'right'],
|
|
193
|
+
description: 'Mouse button to click (default: left)',
|
|
194
|
+
},
|
|
195
|
+
clickCount: { type: 'number', description: 'Number of times to click (default: 1)' },
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
];
|
|
200
|
+
const buildHandlers = (adapter) => {
|
|
201
|
+
const handlers = new Map();
|
|
202
|
+
handlers.set('virtual_start', async (args) => {
|
|
203
|
+
if (args.url) {
|
|
204
|
+
await adapter.loadUrl(args.url);
|
|
205
|
+
}
|
|
206
|
+
else if (args.html) {
|
|
207
|
+
await adapter.loadHtml(args.html);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
throw new Error("Either 'url' or 'html' parameter is required");
|
|
211
|
+
}
|
|
212
|
+
const res = await adapter.start();
|
|
213
|
+
return result.json(res);
|
|
214
|
+
});
|
|
215
|
+
handlers.set('virtual_stop', async () => {
|
|
216
|
+
const res = await adapter.stop();
|
|
217
|
+
return result.json(res);
|
|
218
|
+
});
|
|
219
|
+
handlers.set('virtual_next', async () => {
|
|
220
|
+
const res = await adapter.next();
|
|
221
|
+
return result.json(res);
|
|
222
|
+
});
|
|
223
|
+
handlers.set('virtual_previous', async () => {
|
|
224
|
+
const res = await adapter.previous();
|
|
225
|
+
return result.json(res);
|
|
226
|
+
});
|
|
227
|
+
handlers.set('virtual_act', async () => {
|
|
228
|
+
const res = await adapter.act();
|
|
229
|
+
return result.json(res);
|
|
230
|
+
});
|
|
231
|
+
handlers.set('virtual_interact', async () => {
|
|
232
|
+
const res = await adapter.interact();
|
|
233
|
+
return result.json(res);
|
|
234
|
+
});
|
|
235
|
+
handlers.set('virtual_stop_interacting', async () => {
|
|
236
|
+
const res = await adapter.stopInteracting();
|
|
237
|
+
return result.json(res);
|
|
238
|
+
});
|
|
239
|
+
handlers.set('virtual_press', async (args) => {
|
|
240
|
+
if (!args.key) {
|
|
241
|
+
throw new Error('key parameter is required');
|
|
242
|
+
}
|
|
243
|
+
const res = await adapter.press(args.key);
|
|
244
|
+
return result.json(res);
|
|
245
|
+
});
|
|
246
|
+
handlers.set('virtual_type', async (args) => {
|
|
247
|
+
if (!args.text) {
|
|
248
|
+
throw new Error('text parameter is required');
|
|
249
|
+
}
|
|
250
|
+
const res = await adapter.type(args.text);
|
|
251
|
+
return result.json(res);
|
|
252
|
+
});
|
|
253
|
+
handlers.set('virtual_perform', async (args) => {
|
|
254
|
+
if (!args.command) {
|
|
255
|
+
throw new Error('command parameter is required');
|
|
256
|
+
}
|
|
257
|
+
const res = await adapter.perform(args.command);
|
|
258
|
+
return result.json(res);
|
|
259
|
+
});
|
|
260
|
+
handlers.set('virtual_item_text', async () => {
|
|
261
|
+
const text = await adapter.itemText();
|
|
262
|
+
return result.text(text);
|
|
263
|
+
});
|
|
264
|
+
handlers.set('virtual_last_spoken_phrase', async () => {
|
|
265
|
+
const phrase = await adapter.lastSpokenPhrase();
|
|
266
|
+
return result.text(phrase);
|
|
267
|
+
});
|
|
268
|
+
handlers.set('virtual_spoken_phrase_log', async () => {
|
|
269
|
+
const log = await adapter.spokenPhraseLog();
|
|
270
|
+
return result.json(log);
|
|
271
|
+
});
|
|
272
|
+
handlers.set('virtual_item_text_log', async () => {
|
|
273
|
+
const log = await adapter.itemTextLog();
|
|
274
|
+
return result.json(log);
|
|
275
|
+
});
|
|
276
|
+
handlers.set('virtual_clear_spoken_phrase_log', async () => {
|
|
277
|
+
await adapter.clearSpokenPhraseLog();
|
|
278
|
+
return result.text('Spoken phrase log cleared');
|
|
279
|
+
});
|
|
280
|
+
handlers.set('virtual_clear_item_text_log', async () => {
|
|
281
|
+
await adapter.clearItemTextLog();
|
|
282
|
+
return result.text('Item text log cleared');
|
|
283
|
+
});
|
|
284
|
+
handlers.set('virtual_click', async (args) => {
|
|
285
|
+
const res = await adapter.click({
|
|
286
|
+
button: args.button ?? 'left',
|
|
287
|
+
clickCount: args.clickCount ?? 1,
|
|
288
|
+
});
|
|
289
|
+
return result.json(res);
|
|
290
|
+
});
|
|
291
|
+
return handlers;
|
|
292
|
+
};
|
|
293
|
+
export const createVirtualTools = (adapter) => ({
|
|
294
|
+
tools: defineTools(),
|
|
295
|
+
handlers: buildHandlers(adapter),
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=virtual.tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual.tools.js","sourceRoot":"","sources":["../../../src/screen-readers/virtual/virtual.tools.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAsBnE,eAAO,MAAM,YAAY,QAAO,MAsD/B,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { AuditSession, createAuditTools, createReportTools, listResources, readResource, ToolRegistry, } from '@weaaare/mcp-auditor-core';
|
|
4
|
+
import packageVersion from '../package.json' with { type: 'json' };
|
|
5
|
+
import { getVirtualPromptMessages, listVirtualPrompts } from './prompts/virtual-prompts.js';
|
|
6
|
+
import { VirtualScreenReaderAdapter } from './screen-readers/virtual/virtual.adapter.js';
|
|
7
|
+
import { createVirtualTools } from './screen-readers/virtual/virtual.tools.js';
|
|
8
|
+
export const createServer = () => {
|
|
9
|
+
const server = new Server({
|
|
10
|
+
name: 'mcp-virtual-screen-reader-auditor',
|
|
11
|
+
version: packageVersion.version,
|
|
12
|
+
}, { capabilities: { tools: {}, prompts: {}, resources: {} } });
|
|
13
|
+
const adapter = new VirtualScreenReaderAdapter();
|
|
14
|
+
const session = new AuditSession();
|
|
15
|
+
const registry = new ToolRegistry();
|
|
16
|
+
registry.register(createVirtualTools(adapter));
|
|
17
|
+
registry.register(createAuditTools(session));
|
|
18
|
+
registry.register(createReportTools(session));
|
|
19
|
+
// --- Tools ---
|
|
20
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
21
|
+
tools: registry.listTools(),
|
|
22
|
+
}));
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
24
|
+
const { name, arguments: args } = request.params;
|
|
25
|
+
return registry.callTool(name, args ?? {});
|
|
26
|
+
});
|
|
27
|
+
// --- Prompts ---
|
|
28
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
29
|
+
prompts: listVirtualPrompts(),
|
|
30
|
+
}));
|
|
31
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
32
|
+
const { name, arguments: args } = request.params;
|
|
33
|
+
const messages = getVirtualPromptMessages(name, args ?? {});
|
|
34
|
+
return {
|
|
35
|
+
description: `Audit prompt: ${name}`,
|
|
36
|
+
messages,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
// --- Resources ---
|
|
40
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
41
|
+
resources: listResources(session),
|
|
42
|
+
}));
|
|
43
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
44
|
+
return readResource(request.params.uri, session);
|
|
45
|
+
});
|
|
46
|
+
return server;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weaaare/mcp-virtual-screen-reader-auditor",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server for virtual screen reader accessibility auditing — headless browser-based screen reader simulation that works on any OS",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-virtual-screen-reader-auditor": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"check-types": "tsc --noEmit",
|
|
18
|
+
"lint": "biome check .",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"test": "rstest --passWithNoTests"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@guidepup/virtual-screen-reader": "catalog:",
|
|
24
|
+
"@modelcontextprotocol/sdk": "catalog:",
|
|
25
|
+
"@weaaare/mcp-auditor-core": "workspace:*",
|
|
26
|
+
"playwright-core": "catalog:"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@biomejs/biome": "catalog:",
|
|
30
|
+
"@rstest/core": "catalog:",
|
|
31
|
+
"@types/node": "catalog:",
|
|
32
|
+
"@weaaare/config": "workspace:*",
|
|
33
|
+
"typescript": "catalog:"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"mcp",
|
|
37
|
+
"accessibility",
|
|
38
|
+
"a11y",
|
|
39
|
+
"virtual-screen-reader",
|
|
40
|
+
"screen-reader",
|
|
41
|
+
"wcag",
|
|
42
|
+
"headless"
|
|
43
|
+
],
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/weAAAre/accessibility-ai.git",
|
|
47
|
+
"directory": "packages/mcp-virtual-screen-reader-auditor"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/weAAAre/accessibility-ai/tree/main/packages/mcp-virtual-screen-reader-auditor#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/weAAAre/accessibility-ai/issues"
|
|
52
|
+
},
|
|
53
|
+
"author": "weAAAre <hola@weAAAre.com> (https://weAAAre.com)",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=24"
|
|
56
|
+
}
|
|
57
|
+
}
|