qa-sec-scan-mcp-server
# qa-sec-scan-mcp-server
An MCP server that passively scans HAR files — the kind QA automation already produces (e.g. via Playwright's `recordHar` option) — for common security issues.
**It never sends network requests of its own.** It only analyzes HTTP traffic that already happened, captured in a `.har` file you point it at. That makes it safe to run against any environment, including production, since it can't cause side effects.
## What it catches
| Rule | Category | Severity |
|---|---|---|
| HDR-001 | Missing `Strict-Transport-Security` header | Medium |
| HDR-002 | Request made over plaintext HTTP | High |
| COK-001 | Session cookie missing `Secure`/`HttpOnly`/`SameSite` | High |
| DATA-001 | Secret/credential pattern in response body | Critical |
| DATA-002 | Sensitive-looking parameter in the URL | Medium |
| DATA-003 | Luhn-valid payment card number in response body | Critical |
| CORS-001 | CORS reflects the request's Origin unconditionally | High |
| CORS-002 | Wildcard CORS origin combined with credentials | Critical |
## Setup
```bash
npm install
npm run build
```
## Producing a HAR file from your test suite
This scanner needs response headers, cookies, and response bodies to work — so however you generate the HAR, make sure content isn't stripped out.
### Playwright
```typescript
const context = await browser.newContext({
recordHar: { path: "test-results/network.har" },
// defaults: mode "full", content "embed" for a .har path — includes headers, cookies, and bodies.
// Don't override to mode: "minimal" or content: "omit", or the rules that inspect
// response bodies (DATA-001, DATA-002, DATA-003) and cookies (COK-001) will have nothing to check.
});
// ... run your test, make requests via `context` or any page created from it ...
await context.close(); // the HAR is only written to disk once the context closes
```
If you're using the Playwright Test runner rather than driving `browser`/`context` by hand, the equivalent is setting `recordHar` in your project's `use` config, or per-test via `test.use({ recordHar: { path: "..." } })`.
Other tools that can emit HAR (mitmproxy, browser DevTools' "Save as HAR", `har-recorder` style middlewares) work too — `harParser.ts` reads the standard HAR 1.2 format, it isn't Playwright-specific.
## Using this MCP with an AI client
For interactive, AI-assisted triage — asking an assistant to scan a HAR and explain what it finds, the way this project was built and tested — add the server to your MCP client's config (e.g. Claude Desktop):
```json
{
"mcpServers": {
"qa-sec-scan": {
"command": "node",
"args": ["/absolute/path/to/qa-sec-scan-mcp-server/dist/index.js"]
}
}
}
```
**Restart your client after any rebuild.** MCP clients keep a long-lived server process running; a `tsc` rebuild overwrites the files on disk but does not restart the already-running process, so it'll keep serving stale code until you restart the client.
### Tool: `secscan_scan_har`
**Args:**
- `harFilePath` (string) — absolute path to a `.har` file
- `response_format` (`"markdown"` | `"json"`, default `"markdown"`)
Returns a scan summary (counts by severity) plus a list of findings, each with the rule that fired, the offending request, evidence, and a remediation suggestion. Text responses are capped at the 50 highest-severity findings (worst first); the full, untruncated result set is always available via the tool's structured content, for any client reading that instead of the text.
In practice: point your AI client at a HAR file your test suite produced and ask it to scan for security issues — no manual invocation syntax needed, the assistant calls the tool for you.
## Using this as a CI gate (no AI client needed)
If you want a deterministic pass/fail check in your pipeline instead — build fails if any `critical` finding shows up — use the bundled CLI, which runs the same scan logic directly without going through the MCP protocol at all:
```bash
npm run gate -- path/to/network.har
```
Exits `0` if there are no critical findings, `1` if there are (or if the HAR couldn't be scanned at all — the gate fails closed on errors rather than silently passing).
Example as a step in a CI workflow that already runs Playwright:
```yaml
- name: Run Playwright tests
run: npx playwright test
- name: Security gate on captured HAR
run: npm run gate -- test-results/network.har
```
If your suite produces multiple HAR files (one per test, say), loop the gate command over each path rather than hardcoding one.
## Development
```bash
npm run dev # tsx watch — fast iteration, does NOT type-check
npm run build # tsc — the real correctness gate for the code itself
```
## Architecture
HAR file → harParser.ts → Transaction[] → rules/*.ts (each independent) → scanEngine.ts → ScanReport
│
┌─────────────────────┴─────────────────────┐
│ │
src/tools/scanHar.ts src/cli.ts
(MCP tool, for AI clients) (deterministic CI gate)
Parsers translate raw formats into a normalized `Transaction`. Rules never touch raw HAR shapes — they only see `Transaction`. The scan engine and rule set are shared between both consumers (the MCP tool and the CLI gate); only the presentation and exit-code logic differ.TDQS
Scored across 1 tool
With a single tool there is no risk of overlap or misselection. secscan_scan_har is precisely described as a passive HAR security scanner, making its purpose unmistakable.
The tool name follows a clear snake_case verb_object convention with a consistent secscan_ prefix. Having only one tool means there are no conflicting naming patterns to confuse agents.
One tool is at the low end of the scale and the server name suggests a broader security-scanning purpose, so the surface feels thin. That said, the single tool is substantial and not trivial, so it is borderline rather than severely undersized.
For the described passive HAR-scanning domain, the tool covers the full input-analysis-output flow with a useful format option. The only potential gap is the absence of additional scan types or live-traffic scanning, but those are explicitly outside the tool's stated scope.