nfunc-mcp 0.1.0
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 +395 -0
- package/dist/config/qa-mcp-baseline.eslint.config.js +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/mappers/correlator.d.ts +28 -0
- package/dist/mappers/correlator.js +132 -0
- package/dist/mappers/correlator.js.map +1 -0
- package/dist/mappers/defectFormatter.d.ts +15 -0
- package/dist/mappers/defectFormatter.js +209 -0
- package/dist/mappers/defectFormatter.js.map +1 -0
- package/dist/mappers/priorityMapper.d.ts +6 -0
- package/dist/mappers/priorityMapper.js +37 -0
- package/dist/mappers/priorityMapper.js.map +1 -0
- package/dist/tools/accessibility.d.ts +2 -0
- package/dist/tools/accessibility.js +63 -0
- package/dist/tools/accessibility.js.map +1 -0
- package/dist/tools/lighthouse.d.ts +2 -0
- package/dist/tools/lighthouse.js +61 -0
- package/dist/tools/lighthouse.js.map +1 -0
- package/dist/tools/qaGate.d.ts +2 -0
- package/dist/tools/qaGate.js +383 -0
- package/dist/tools/qaGate.js.map +1 -0
- package/dist/tools/staticAnalysis.d.ts +2 -0
- package/dist/tools/staticAnalysis.js +172 -0
- package/dist/tools/staticAnalysis.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/eslintConfigDetector.d.ts +5 -0
- package/dist/utils/eslintConfigDetector.js +21 -0
- package/dist/utils/eslintConfigDetector.js.map +1 -0
- package/dist/utils/outputParsers.d.ts +56 -0
- package/dist/utils/outputParsers.js +184 -0
- package/dist/utils/outputParsers.js.map +1 -0
- package/dist/utils/reportGenerator.d.ts +21 -0
- package/dist/utils/reportGenerator.js +291 -0
- package/dist/utils/reportGenerator.js.map +1 -0
- package/dist/utils/shellRunner.d.ts +12 -0
- package/dist/utils/shellRunner.js +31 -0
- package/dist/utils/shellRunner.js.map +1 -0
- package/dist/utils/toolResponse.d.ts +12 -0
- package/dist/utils/toolResponse.js +26 -0
- package/dist/utils/toolResponse.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# qa-mcp
|
|
2
|
+
|
|
3
|
+
A local MCP server that gives Claude (or any MCP client) a full non-functional QA toolkit. Run Lighthouse, WCAG accessibility checks, and static code analysis — individually or all at once — and get back structured, prioritised findings you can act on immediately.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of contents
|
|
8
|
+
|
|
9
|
+
1. [What it does](#what-it-does)
|
|
10
|
+
2. [Prerequisites](#prerequisites)
|
|
11
|
+
3. [Install & build](#install--build)
|
|
12
|
+
4. [Register with Claude Code](#register-with-claude-code)
|
|
13
|
+
5. [Tools](#tools)
|
|
14
|
+
6. [run_qa_gate — the main tool](#run_qa_gate--the-main-tool)
|
|
15
|
+
- [Inputs](#inputs)
|
|
16
|
+
- [Release readiness tiers](#release-readiness-tiers)
|
|
17
|
+
- [Composite score](#composite-score)
|
|
18
|
+
- [Scorecard](#scorecard)
|
|
19
|
+
- [Cross-tool corroboration](#cross-tool-corroboration)
|
|
20
|
+
- [HTML report](#html-report)
|
|
21
|
+
- [Output shape](#output-shape)
|
|
22
|
+
7. [Individual tools](#individual-tools)
|
|
23
|
+
8. [Priority system](#priority-system)
|
|
24
|
+
9. [Project layout](#project-layout)
|
|
25
|
+
10. [How to prompt](#how-to-prompt)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## What it does
|
|
30
|
+
|
|
31
|
+
`qa-mcp` wires four QA tools into Claude's tool-use loop:
|
|
32
|
+
|
|
33
|
+
| Capability | Tools | What it checks |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Performance | Lighthouse | LCP, TTI, TBT, CLS, bundle size, caching |
|
|
36
|
+
| Accessibility | Lighthouse + pa11y | WCAG 2 AA violations, ARIA, contrast, labels |
|
|
37
|
+
| SEO | Lighthouse | Crawlability, robots.txt, meta, link text |
|
|
38
|
+
| Best practices | Lighthouse | HTTPS, deprecated APIs, third-party cookies |
|
|
39
|
+
| Code quality | ESLint | Dead code, undeclared vars, swallowed errors |
|
|
40
|
+
| Security patterns | Semgrep | OWASP JS/TS patterns |
|
|
41
|
+
|
|
42
|
+
The `run_qa_gate` orchestrator runs all of them in parallel, cross-correlates findings across tools, and produces a single structured report with a release readiness verdict, a composite health score, a per-tool scorecard, and a browser-openable HTML report.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Prerequisites
|
|
47
|
+
|
|
48
|
+
The following CLI tools must be available on your PATH:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g lighthouse # Lighthouse
|
|
52
|
+
npm install -g pa11y # pa11y
|
|
53
|
+
npm install -g eslint # ESLint
|
|
54
|
+
brew install semgrep # Semgrep (or pip install semgrep)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Verify each is reachable:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
lighthouse --version
|
|
61
|
+
pa11y --version
|
|
62
|
+
eslint --version
|
|
63
|
+
semgrep --version
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If a tool is missing, the gate still runs — that tool's scorecard entry will show `UNAVAILABLE` and its findings are omitted from the report.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Install & build
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone <repo-url>
|
|
74
|
+
cd qa-mcp
|
|
75
|
+
npm install
|
|
76
|
+
npm run build
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Scripts
|
|
80
|
+
|
|
81
|
+
| Script | Purpose |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `npm run build` | Compile TypeScript → `dist/` |
|
|
84
|
+
| `npm start` | Run the compiled server |
|
|
85
|
+
| `npm run dev` | Run from source with hot reload (`tsx watch`) |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Register with Claude Code
|
|
90
|
+
|
|
91
|
+
### Option A — CLI (recommended)
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
claude mcp add qa-mcp -- node /absolute/path/to/qa-mcp/dist/index.js
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Option B — Manual config
|
|
98
|
+
|
|
99
|
+
Add to `~/.claude.json` under `mcpServers`:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"qa-mcp": {
|
|
105
|
+
"command": "node",
|
|
106
|
+
"args": ["/absolute/path/to/qa-mcp/dist/index.js"]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Verify the connection
|
|
113
|
+
|
|
114
|
+
1. Run `/mcp` in Claude Code — `qa-mcp` should show as `connected`.
|
|
115
|
+
2. Ask Claude: *"Call the qa-mcp ping tool."*
|
|
116
|
+
3. Expected response:
|
|
117
|
+
```json
|
|
118
|
+
{ "status": "ok", "timestamp": "2026-05-20T12:00:00.000Z" }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Tools
|
|
124
|
+
|
|
125
|
+
| Tool | Description | Inputs |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `ping` | Health check — confirms the server is up | — |
|
|
128
|
+
| `run_lighthouse` | Full Lighthouse audit for a URL | `url` |
|
|
129
|
+
| `run_accessibility_check` | pa11y WCAG audit for a URL | `url`, `standard` (optional), `ignore` (optional) |
|
|
130
|
+
| `run_static_analysis` | ESLint + Semgrep scan for a local codebase | `path` |
|
|
131
|
+
| `run_qa_gate` | All tools in parallel + correlation + HTML report | `url` and/or `path` |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## run_qa_gate — the main tool
|
|
136
|
+
|
|
137
|
+
This is the tool to reach for in nearly every QA workflow. It replaces running tools individually and adds cross-tool intelligence on top.
|
|
138
|
+
|
|
139
|
+
### Inputs
|
|
140
|
+
|
|
141
|
+
Both inputs are **optional** — provide whichever you have. At least one is required.
|
|
142
|
+
|
|
143
|
+
| Input | Type | When to provide |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `url` | string (URL) | You have a running page — production, staging, preview URL, or localhost. Enables Lighthouse and pa11y. |
|
|
146
|
+
| `path` | string (path) | You have a local codebase. Enables ESLint and Semgrep. |
|
|
147
|
+
| `context` | string | Optional. Free-text description of the project (e.g. `"React e-commerce checkout"`). Helps Claude interpret results. |
|
|
148
|
+
|
|
149
|
+
**URL only** — browser-based checks, static analysis skipped:
|
|
150
|
+
```
|
|
151
|
+
QA snapshot — https://staging.myapp.com
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Path only** — static analysis only, browser checks skipped:
|
|
155
|
+
```
|
|
156
|
+
QA snapshot — /path/to/my-feature-branch
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Both** — full suite:
|
|
160
|
+
```
|
|
161
|
+
QA snapshot — https://staging.myapp.com, code at /path/to/repo
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Release readiness tiers
|
|
165
|
+
|
|
166
|
+
The `release_readiness` field replaces a binary pass/fail with four actionable tiers:
|
|
167
|
+
|
|
168
|
+
| Value | Meaning | Condition |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `BLOCKED` | Cannot ship — P1 issues exist | Any P1 finding |
|
|
171
|
+
| `CONDITIONAL` | Shippable with caveats — track P2s before merging | P2 findings, no P1s |
|
|
172
|
+
| `ADVISORY` | Safe to ship — P3s are tech debt to log | Only P3 findings |
|
|
173
|
+
| `CLEAR` | No issues detected | Zero findings |
|
|
174
|
+
|
|
175
|
+
### Composite score
|
|
176
|
+
|
|
177
|
+
A single `composite_score` (0–100) gives a continuous health measure across all tools.
|
|
178
|
+
|
|
179
|
+
**Formula:** Start at 100, deduct by finding severity:
|
|
180
|
+
|
|
181
|
+
| Priority | Deduction |
|
|
182
|
+
|---|---|
|
|
183
|
+
| P1 | −15 per finding |
|
|
184
|
+
| P2 | −7 per finding |
|
|
185
|
+
| P3 | −3 per finding |
|
|
186
|
+
|
|
187
|
+
Score is floored at 0. Tracks improvement over time — a score trending upward sprint-over-sprint is a healthy signal.
|
|
188
|
+
|
|
189
|
+
### Scorecard
|
|
190
|
+
|
|
191
|
+
A compact `scorecard` array gives a one-line status per tool:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
[
|
|
195
|
+
{ "tool": "Lighthouse", "gate": "WARN", "score": 75,
|
|
196
|
+
"breakdown": { "performance": 52, "accessibility": 98, "seo": 100, "best-practices": 58 } },
|
|
197
|
+
{ "tool": "pa11y", "gate": "PASS", "issues": 0 },
|
|
198
|
+
{ "tool": "ESLint / Semgrep", "gate": "SKIPPED" }
|
|
199
|
+
]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Gate values:
|
|
203
|
+
|
|
204
|
+
| Gate | Meaning |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `PASS` | No issues at this tool's threshold |
|
|
207
|
+
| `WARN` | Issues exist but below the FAIL threshold |
|
|
208
|
+
| `FAIL` | Issues at P1 level (or Lighthouse avg < 50) |
|
|
209
|
+
| `SKIPPED` | Input not provided (URL or path not supplied) |
|
|
210
|
+
| `UNAVAILABLE` | Tool was invoked but is not installed or errored |
|
|
211
|
+
|
|
212
|
+
### Cross-tool corroboration
|
|
213
|
+
|
|
214
|
+
When Lighthouse and pa11y independently flag the same accessibility gap, those findings are:
|
|
215
|
+
|
|
216
|
+
1. **Merged** into a single entry in `corroborated_findings`
|
|
217
|
+
2. **Priority-promoted** one tier (P3→P2, P2→P1)
|
|
218
|
+
3. **Annotated** with `confidence: "high"` and `confirmed_by: ["lighthouse", "pa11y"]`
|
|
219
|
+
|
|
220
|
+
These are the highest-confidence findings in any report — two independent tools agreeing is stronger evidence than either alone. They appear in their own dedicated section above all other findings, and bubble to the top of `top_issues`.
|
|
221
|
+
|
|
222
|
+
**Corroboration mapping (Rule 1):**
|
|
223
|
+
|
|
224
|
+
| Lighthouse audit | pa11y technique |
|
|
225
|
+
|---|---|
|
|
226
|
+
| `color-contrast` | `.G18`, `.G145`, `.G174` |
|
|
227
|
+
| `image-alt` | `.H37`, `.H67`, `.F65` |
|
|
228
|
+
| `label` | `.H44`, `.F68`, `.H91.Input` |
|
|
229
|
+
| `link-name` | `.H30`, `.H91.A.` |
|
|
230
|
+
| `html-has-lang` | `.H57` |
|
|
231
|
+
| `button-name` | `.H91.Button` |
|
|
232
|
+
| *(and more)* | |
|
|
233
|
+
|
|
234
|
+
**Performance ↔ code linkage (Rule 2):** If a Lighthouse performance finding's display value contains a filename that also appears in a static analysis finding, the static finding is added as `related_findings` on the Lighthouse entry. Findings are not merged — they remain linked by reference.
|
|
235
|
+
|
|
236
|
+
### HTML report
|
|
237
|
+
|
|
238
|
+
Every `run_qa_gate` call automatically writes a self-contained HTML file to `/tmp` and returns its path as `report_file`:
|
|
239
|
+
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"report_file": "file:///tmp/qa-report-myapp-com-1234567890.html"
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Open the path in any browser to get:
|
|
247
|
+
|
|
248
|
+
- Release readiness banner (colour-coded)
|
|
249
|
+
- Composite score gauge (SVG arc, 0–100)
|
|
250
|
+
- Per-tool scorecard table
|
|
251
|
+
- Cross-confirmed findings section (highlighted)
|
|
252
|
+
- Collapsible finding cards grouped by P1 / P2 / P3
|
|
253
|
+
- Evidence and selector for each finding
|
|
254
|
+
|
|
255
|
+
No server required — the file is fully self-contained with inline CSS.
|
|
256
|
+
|
|
257
|
+
### Output shape
|
|
258
|
+
|
|
259
|
+
```jsonc
|
|
260
|
+
{
|
|
261
|
+
"release_readiness": "BLOCKED", // BLOCKED | CONDITIONAL | ADVISORY | CLEAR
|
|
262
|
+
"composite_score": 22, // 0–100
|
|
263
|
+
"report_file": "file:///tmp/qa-report-xxx.html",
|
|
264
|
+
"scorecard": [ ... ], // per-tool gate + score/issues
|
|
265
|
+
"eslint_config_used": "project", // present only when path was supplied
|
|
266
|
+
"summary": "110 findings (101 P1, 9 P2) across 2 tools. ...",
|
|
267
|
+
"corroborated_findings": [ ... ], // cross-confirmed, confidence: "high"
|
|
268
|
+
"top_issues": [ ... ], // top 3 findings (corroborated first)
|
|
269
|
+
"all_findings": [ ... ], // all findings sorted by priority
|
|
270
|
+
"correlations_found": 1,
|
|
271
|
+
"errors": [ ... ] // present only if a tool errored
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Each finding:
|
|
276
|
+
|
|
277
|
+
```jsonc
|
|
278
|
+
{
|
|
279
|
+
"priority": "P1", // P1 | P2 | P3
|
|
280
|
+
"title": "Largest Contentful Paint",
|
|
281
|
+
"description": "Users see main content 34s after navigation...",
|
|
282
|
+
"evidence": { "audit_id": "largest-contentful-paint", "value": "34.3 s" },
|
|
283
|
+
"source_tool": "lighthouse",
|
|
284
|
+
// corroborated findings also have:
|
|
285
|
+
"confirmed_by": ["lighthouse", "pa11y"],
|
|
286
|
+
"confidence": "high"
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Individual tools
|
|
293
|
+
|
|
294
|
+
### run_lighthouse
|
|
295
|
+
|
|
296
|
+
Runs a full Lighthouse audit against a URL.
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
Run Lighthouse on https://myapp.com
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Returns: `url`, `scores` (per category), `ttfb_ms`, `findings` (priority-ordered).
|
|
303
|
+
|
|
304
|
+
### run_accessibility_check
|
|
305
|
+
|
|
306
|
+
Runs pa11y against a URL at WCAG 2 AA by default. Returns only violations (errors) — use the CLI directly with `--include-notices --include-warnings` for the full checklist.
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
Run an accessibility check on https://myapp.com
|
|
310
|
+
Run accessibility check at AAA standard on https://myapp.com
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Returns: `url`, `standard`, `violation_count`, `findings`.
|
|
314
|
+
|
|
315
|
+
### run_static_analysis
|
|
316
|
+
|
|
317
|
+
Runs ESLint and Semgrep in parallel against a local directory. Automatically uses the project's own ESLint config if one is found; otherwise falls back to a QA-focused baseline config.
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
Run static analysis on /path/to/repo
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Returns: `path`, `tools_run`, `eslint_config_used`, `issue_count`, `findings`, `warnings`.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Priority system
|
|
328
|
+
|
|
329
|
+
| Priority | Meaning | Lighthouse threshold | WCAG level | ESLint / Semgrep |
|
|
330
|
+
|---|---|---|---|---|
|
|
331
|
+
| P1 | Blocker — fix before shipping | Score < 50 | Level A | Semgrep security, ESLint error |
|
|
332
|
+
| P2 | Warning — track before merging | Score 50–79 | Level AA | ESLint warning |
|
|
333
|
+
| P3 | Advisory — log as tech debt | Score 80–89 | Level AAA | — |
|
|
334
|
+
| *(suppressed)* | Passing — not reported | Score ≥ 90 | — | — |
|
|
335
|
+
|
|
336
|
+
Corroborated findings are promoted one tier above where either tool would place them individually.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Project layout
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
qa-mcp/
|
|
344
|
+
├── src/
|
|
345
|
+
│ ├── index.ts # MCP server bootstrap + tool registration
|
|
346
|
+
│ ├── types.ts # Shared types (Finding, Priority)
|
|
347
|
+
│ ├── config/
|
|
348
|
+
│ │ └── qa-mcp-baseline.eslint.config.js # Fallback ESLint config
|
|
349
|
+
│ ├── tools/
|
|
350
|
+
│ │ ├── qaGate.ts # Orchestrator — runs all tools, builds report
|
|
351
|
+
│ │ ├── lighthouse.ts # run_lighthouse tool
|
|
352
|
+
│ │ ├── accessibility.ts # run_accessibility_check tool
|
|
353
|
+
│ │ └── staticAnalysis.ts # run_static_analysis tool
|
|
354
|
+
│ ├── mappers/
|
|
355
|
+
│ │ ├── correlator.ts # Cross-tool correlation engine (Rule 1 + 2)
|
|
356
|
+
│ │ ├── defectFormatter.ts # Raw tool output → Finding objects
|
|
357
|
+
│ │ └── priorityMapper.ts # Score/severity → P1/P2/P3
|
|
358
|
+
│ └── utils/
|
|
359
|
+
│ ├── reportGenerator.ts # HTML report builder
|
|
360
|
+
│ ├── shellRunner.ts # CLI execution with timeout + error handling
|
|
361
|
+
│ ├── outputParsers.ts # JSON parsers for each tool's output
|
|
362
|
+
│ ├── eslintConfigDetector.ts # Detects project ESLint config
|
|
363
|
+
│ └── toolResponse.ts # MCP error response helpers
|
|
364
|
+
├── dist/ # Compiled output (gitignored)
|
|
365
|
+
├── package.json
|
|
366
|
+
├── tsconfig.json
|
|
367
|
+
└── README.md
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## How to prompt
|
|
373
|
+
|
|
374
|
+
The shortest working prompts:
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+
# Full suite
|
|
378
|
+
QA snapshot — https://myapp.com, code at /path/to/repo
|
|
379
|
+
|
|
380
|
+
# URL only (Lighthouse + pa11y)
|
|
381
|
+
QA snapshot — https://myapp.com
|
|
382
|
+
|
|
383
|
+
# Local branch only (ESLint + Semgrep)
|
|
384
|
+
QA snapshot — /path/to/my-feature-branch
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Alternative trigger phrases (all invoke `run_qa_gate`):
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
Health check on https://myapp.com
|
|
391
|
+
Is https://myapp.com ready to ship? Code at /path/to/repo
|
|
392
|
+
Any red flags? /path/to/repo
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
After the run, Claude will surface the `report_file` path. Open it in your browser for the full visual dashboard.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// QA MCP baseline ESLint config — purely bug-risk rules, no style/formatting.
|
|
2
|
+
// Targets JS/JSX files only; TypeScript files require @typescript-eslint/parser.
|
|
3
|
+
// Used as fallback when the target repo has no ESLint config of its own.
|
|
4
|
+
export default [
|
|
5
|
+
{
|
|
6
|
+
files: ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.jsx"],
|
|
7
|
+
ignores: ["**/node_modules/**", "**/dist/**"],
|
|
8
|
+
rules: {
|
|
9
|
+
"no-unused-vars": "error",
|
|
10
|
+
"no-undef": "error",
|
|
11
|
+
eqeqeq: "error",
|
|
12
|
+
"no-unreachable": "error",
|
|
13
|
+
"no-console": "warn",
|
|
14
|
+
"no-empty": "error",
|
|
15
|
+
"no-constant-condition": "error",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { registerLighthouseTool } from "./tools/lighthouse.js";
|
|
5
|
+
import { registerAccessibilityTool } from "./tools/accessibility.js";
|
|
6
|
+
import { registerStaticAnalysisTool } from "./tools/staticAnalysis.js";
|
|
7
|
+
import { registerQaGateTool } from "./tools/qaGate.js";
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: "qa-mcp",
|
|
10
|
+
version: "0.1.0",
|
|
11
|
+
});
|
|
12
|
+
server.registerTool("ping", {
|
|
13
|
+
description: "Health-check tool. Returns ok status and current ISO timestamp.",
|
|
14
|
+
inputSchema: {},
|
|
15
|
+
}, async () => {
|
|
16
|
+
const payload = {
|
|
17
|
+
status: "ok",
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
registerLighthouseTool(server);
|
|
25
|
+
registerAccessibilityTool(server);
|
|
26
|
+
registerStaticAnalysisTool(server);
|
|
27
|
+
registerQaGateTool(server);
|
|
28
|
+
async function main() {
|
|
29
|
+
const transport = new StdioServerTransport();
|
|
30
|
+
await server.connect(transport);
|
|
31
|
+
}
|
|
32
|
+
main().catch((err) => {
|
|
33
|
+
console.error("qa-mcp fatal error:", err);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,YAAY,CACjB,MAAM,EACN;IACE,WAAW,EAAE,iEAAiE;IAC9E,WAAW,EAAE,EAAE;CAChB,EACD,KAAK,IAAI,EAAE;IACT,MAAM,OAAO,GAAG;QACd,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAClC,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Finding } from "../types.js";
|
|
2
|
+
export interface CorrelatedFinding extends Finding {
|
|
3
|
+
id: string;
|
|
4
|
+
source_tool: string;
|
|
5
|
+
confirmed_by?: string[];
|
|
6
|
+
related_findings?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface ToolReports {
|
|
9
|
+
lighthouse: {
|
|
10
|
+
scores: Record<string, number>;
|
|
11
|
+
ttfb_ms: number | null;
|
|
12
|
+
findings: Finding[];
|
|
13
|
+
} | null;
|
|
14
|
+
a11y: {
|
|
15
|
+
violation_count: number;
|
|
16
|
+
findings: Finding[];
|
|
17
|
+
} | null;
|
|
18
|
+
static: {
|
|
19
|
+
issue_count: number;
|
|
20
|
+
findings: Finding[];
|
|
21
|
+
} | null;
|
|
22
|
+
}
|
|
23
|
+
export interface CorrelatorResult {
|
|
24
|
+
correlated_findings: CorrelatedFinding[];
|
|
25
|
+
unique_findings: CorrelatedFinding[];
|
|
26
|
+
correlations_count: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function correlate(reports: ToolReports): CorrelatorResult;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const PRIORITY_ORDER = { P1: 0, P2: 1, P3: 2 };
|
|
2
|
+
function promotePriority(p) {
|
|
3
|
+
if (p === "P3")
|
|
4
|
+
return "P2";
|
|
5
|
+
if (p === "P2")
|
|
6
|
+
return "P1";
|
|
7
|
+
return "P1";
|
|
8
|
+
}
|
|
9
|
+
// Maps Lighthouse accessibility audit IDs to substrings that appear inside the
|
|
10
|
+
// pa11y rule_code for the same class of issue. A leading "." prevents matching
|
|
11
|
+
// partial segment names (e.g. ".H44" won't accidentally match ".1H44").
|
|
12
|
+
const LH_TO_PA11Y_SUBSTRINGS = {
|
|
13
|
+
"color-contrast": [".G18", ".G145", ".G174"],
|
|
14
|
+
"image-alt": [".H37", ".H67", ".F65"],
|
|
15
|
+
label: [".H44", ".F68", ".H91.Input", ".H91.Select", ".H91.Textarea"],
|
|
16
|
+
"link-name": [".H30", ".H91.A."],
|
|
17
|
+
"document-title": [".H25", ".F89"],
|
|
18
|
+
"html-has-lang": [".H57"],
|
|
19
|
+
"frame-title": [".H64"],
|
|
20
|
+
"button-name": [".H91.Button"],
|
|
21
|
+
"select-name": [".H91.Select"],
|
|
22
|
+
"duplicate-id-aria": [".H93", ".F77"],
|
|
23
|
+
};
|
|
24
|
+
// Lighthouse performance audit IDs where Rule 2 (code linkage) is relevant.
|
|
25
|
+
const PERFORMANCE_AUDIT_IDS = new Set([
|
|
26
|
+
"render-blocking-resources",
|
|
27
|
+
"unused-javascript",
|
|
28
|
+
"unused-css-rules",
|
|
29
|
+
"bootup-time",
|
|
30
|
+
"mainthread-work-breakdown",
|
|
31
|
+
"total-blocking-time",
|
|
32
|
+
]);
|
|
33
|
+
function makeId(tool, f) {
|
|
34
|
+
const e = f.evidence;
|
|
35
|
+
if (tool === "lighthouse")
|
|
36
|
+
return `lh:${String(e["audit_id"] ?? f.title)}`;
|
|
37
|
+
if (tool === "a11y") {
|
|
38
|
+
const code = String(e["rule_code"] ?? "").split(".").slice(-2).join(".");
|
|
39
|
+
const sel = String(e["selector"] ?? "").slice(0, 16);
|
|
40
|
+
return `a11y:${code}:${sel}`;
|
|
41
|
+
}
|
|
42
|
+
const basename = String(e["file"] ?? "").split("/").pop() ?? "";
|
|
43
|
+
return `static:${String(e["source"] ?? "")}:${basename}:${String(e["line"] ?? "")}`;
|
|
44
|
+
}
|
|
45
|
+
function tag(tool, findings) {
|
|
46
|
+
return findings.map((f) => ({ ...f, id: makeId(tool, f), source_tool: tool }));
|
|
47
|
+
}
|
|
48
|
+
// Rule 1 — Double-confirmed accessibility:
|
|
49
|
+
// A Lighthouse accessibility finding and a pa11y finding that cover the same
|
|
50
|
+
// WCAG technique are merged into one finding with priority promoted one tier
|
|
51
|
+
// and confirmed_by set to both tools.
|
|
52
|
+
function applyRule1(lhFindings, a11yFindings) {
|
|
53
|
+
const correlated = [];
|
|
54
|
+
const consumedLhIds = new Set();
|
|
55
|
+
const consumedA11yIds = new Set();
|
|
56
|
+
for (const lhF of lhFindings) {
|
|
57
|
+
const auditId = String(lhF.evidence["audit_id"] ?? "");
|
|
58
|
+
const substrings = LH_TO_PA11Y_SUBSTRINGS[auditId];
|
|
59
|
+
if (!substrings)
|
|
60
|
+
continue;
|
|
61
|
+
for (const a11yF of a11yFindings) {
|
|
62
|
+
if (consumedA11yIds.has(a11yF.id))
|
|
63
|
+
continue;
|
|
64
|
+
const ruleCode = String(a11yF.evidence["rule_code"] ?? "");
|
|
65
|
+
if (!substrings.some((s) => ruleCode.includes(s)))
|
|
66
|
+
continue;
|
|
67
|
+
// Use the better (lower index = higher priority) of the two raw priorities
|
|
68
|
+
// as the base, then promote it one tier.
|
|
69
|
+
const basePriority = PRIORITY_ORDER[lhF.priority] <= PRIORITY_ORDER[a11yF.priority]
|
|
70
|
+
? lhF.priority
|
|
71
|
+
: a11yF.priority;
|
|
72
|
+
correlated.push({
|
|
73
|
+
id: `corr:lh+a11y:${auditId}`,
|
|
74
|
+
source_tool: "lighthouse+pa11y",
|
|
75
|
+
priority: promotePriority(basePriority),
|
|
76
|
+
title: lhF.title,
|
|
77
|
+
description: `[Lighthouse] ${lhF.description} ` +
|
|
78
|
+
`[pa11y] ${a11yF.description} ` +
|
|
79
|
+
`Two independent tools flagged the same accessibility gap — ` +
|
|
80
|
+
`this cross-tool confirmation increases confidence that the issue is real and affects real users.`,
|
|
81
|
+
evidence: {
|
|
82
|
+
...lhF.evidence,
|
|
83
|
+
pa11y_rule_code: ruleCode,
|
|
84
|
+
pa11y_selector: a11yF.evidence["selector"] ?? "",
|
|
85
|
+
},
|
|
86
|
+
confirmed_by: ["lighthouse", "pa11y"],
|
|
87
|
+
});
|
|
88
|
+
consumedLhIds.add(lhF.id);
|
|
89
|
+
consumedA11yIds.add(a11yF.id);
|
|
90
|
+
break; // one correlation per Lighthouse finding
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { correlated, consumedLhIds, consumedA11yIds };
|
|
94
|
+
}
|
|
95
|
+
// Rule 2 — Performance ↔ code linkage:
|
|
96
|
+
// If a Lighthouse performance finding's description or display value contains a
|
|
97
|
+
// filename that also appears in a static analysis finding, the static finding is
|
|
98
|
+
// added as a related_finding on the Lighthouse entry.
|
|
99
|
+
// Note: full coverage requires the Lighthouse parser to extract resource URLs
|
|
100
|
+
// from audit detail items — the current parser only surfaces displayValue, so
|
|
101
|
+
// matches depend on whether filenames appear there.
|
|
102
|
+
function applyRule2(lhFindings, staticFindings) {
|
|
103
|
+
if (staticFindings.length === 0)
|
|
104
|
+
return lhFindings;
|
|
105
|
+
return lhFindings.map((lhF) => {
|
|
106
|
+
const auditId = String(lhF.evidence["audit_id"] ?? "");
|
|
107
|
+
if (!PERFORMANCE_AUDIT_IDS.has(auditId))
|
|
108
|
+
return lhF;
|
|
109
|
+
const haystack = `${lhF.description} ${String(lhF.evidence["value"] ?? "")}`.toLowerCase();
|
|
110
|
+
const related = staticFindings
|
|
111
|
+
.filter((sf) => {
|
|
112
|
+
const basename = String(sf.evidence["file"] ?? "").split("/").pop() ?? "";
|
|
113
|
+
return basename.length > 3 && haystack.includes(basename.toLowerCase());
|
|
114
|
+
})
|
|
115
|
+
.map((sf) => sf.id);
|
|
116
|
+
return related.length > 0 ? { ...lhF, related_findings: related } : lhF;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
export function correlate(reports) {
|
|
120
|
+
const lhTagged = tag("lighthouse", reports.lighthouse?.findings ?? []);
|
|
121
|
+
const a11yTagged = tag("a11y", reports.a11y?.findings ?? []);
|
|
122
|
+
const staticTagged = tag("static", reports.static?.findings ?? []);
|
|
123
|
+
const { correlated, consumedLhIds, consumedA11yIds } = applyRule1(lhTagged, a11yTagged);
|
|
124
|
+
const remainingLh = applyRule2(lhTagged.filter((f) => !consumedLhIds.has(f.id)), staticTagged);
|
|
125
|
+
const remainingA11y = a11yTagged.filter((f) => !consumedA11yIds.has(f.id));
|
|
126
|
+
return {
|
|
127
|
+
correlated_findings: correlated,
|
|
128
|
+
unique_findings: [...remainingLh, ...remainingA11y, ...staticTagged],
|
|
129
|
+
correlations_count: correlated.length,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=correlator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/mappers/correlator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LighthouseAuditRef, Pa11yViolation } from "../utils/outputParsers.js";
|
|
2
|
+
import type { Finding } from "../types.js";
|
|
3
|
+
export declare function formatLighthouseFinding(audit: LighthouseAuditRef): Finding | null;
|
|
4
|
+
export interface StaticAnalysisIssue {
|
|
5
|
+
source: "eslint" | "semgrep";
|
|
6
|
+
file: string;
|
|
7
|
+
line: number;
|
|
8
|
+
column?: number;
|
|
9
|
+
ruleId: string;
|
|
10
|
+
message: string;
|
|
11
|
+
severity: number | string;
|
|
12
|
+
category?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function formatStaticAnalysisFinding(issue: StaticAnalysisIssue): Finding | null;
|
|
15
|
+
export declare function formatA11yFinding(violation: Pa11yViolation): Finding | null;
|