qa-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@qa-mcprun the full QA suite and diff against last run"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
qa-mcp
Automated QA for a .NET microservice backend (several independent services, each with its own Swagger/OpenAPI document) and a React frontend, running against stage, exposed to an MCP client over stdio.
The one architectural rule
MCP is a thin layer on top of the test engine. The engine does not depend on the model.
Tests are never generated by an LLM at call time. They are either derived deterministically from
OpenAPI, or written by hand as YAML flows / Playwright specs. That is what makes two consecutive
runs comparable — and comparability is the entire value of the tool. If every run produced a
different set of assertions, qa_diff could not tell a regression from noise.
Consequence: everything under src/api, src/flows, src/ui and src/report runs perfectly well
from CI without an MCP client. src/index.ts only registers tools and shrinks the output.
Related MCP server: Argus
Install
npm install
npm run buildRequires Node ≥ 20. npm install also pulls Playwright; download the browser once with:
npx playwright install chromiumConfigure
qa.config.json is the single source of truth. Its path comes from QA_MCP_CONFIG, defaulting to
./qa.config.json. Start from the example:
cp qa.config.example.json qa.config.jsonSection | What it does |
| Free-form label stored in every run report. |
|
|
|
|
|
|
|
|
| Real values used to fill required parameters, keyed by parameter name. |
| Where runs, HTML reports and screenshots are written. Default |
Secrets never live in the config
Any string starting with env: is read from the environment; if the variable is unset, startup
fails with an explicit message naming the field and the variable.
"password": "env:QA_ADMIN_PASSWORD"export QA_ADMIN_PASSWORD=...
export QA_CUSTOMER_PASSWORD=...
export QA_CLIENT_SECRET=...Register the server in an MCP client
command + args, transport stdio:
{
"mcpServers": {
"qa-mcp": {
"command": "node",
"args": ["G:/mcp/qatester/dist/index.js"],
"env": {
"QA_MCP_CONFIG": "G:/mcp/qatester/qa.config.json",
"QA_ADMIN_PASSWORD": "...",
"QA_CUSTOMER_PASSWORD": "...",
"QA_CLIENT_SECRET": "..."
}
}
}
}Claude Code CLI equivalent:
claude mcp add qa-mcp -- node G:/mcp/qatester/dist/index.jsVerify the handshake at any time without touching stage:
npm run smokeTools
Tool | Input | What it does |
|
| Fetches every Swagger document, reports endpoints per service, planned assertions, operations skipped by policy with the reason, and services that could not be reached. Sends no request to the endpoints. |
|
| Generates and runs the API matrix. Mutating endpoints are skipped while |
|
| Runs |
|
| Playwright specs and/or the automatic crawl. |
|
| Full pass, then an automatic diff against the previous stored run. Release gate. |
|
| Reads a stored run with filters. Use it when a digest says results were truncated. |
|
| Compares two runs by stable test id. |
Every run tool returns a digest, not the raw results: the summary, failures grouped by service,
at most 40 failures sorted critical-first, how many were truncated, and the runId to drill into
with qa_report. A full pass over several services produces thousands of assertions; returning all
of them would bury the signal.
What gets tested
Generated API tests
Per operation, from the OpenAPI document:
Check | Assertion | Severity |
| Valid request → status must be declared in the spec and the body must validate against that status' schema | major |
| Secured operation called with no token → anything other than 401/403 is a leak | critical |
| Malformed value in a required typed parameter → expect 400/404/422 | major |
| Response time over | minor |
Any 5xx is an unconditional critical failure, including when the input was deliberately broken. A well-behaved service answers 400, not 500. On a .NET backend this single rule is the highest-yield automated check there is — it drags unhandled exceptions straight out of the framework.
Parameter values come from config.samples (by parameter name) first, then enum[0], default,
example, then a format/type heuristic (uuid → zero-uuid, date → today, integer → 1, …).
Malformed values match the type: uuid → not-a-uuid, numeric → not-a-number, date →
31-31-9999.
Each test carries a stable id — service:METHOD:/path#check — with no timestamp and no random
value in it. qa_diff depends entirely on that.
One valid request produces both the contract and perf results, so an operation costs at most
three HTTP calls (valid, unauthenticated, malformed).
Safety model — read this before pointing it at anything
Running generated tests against stage can destroy data or fire notifications at real users.
With
policy.readOnly: true(the default) onlyGET/HEAD/OPTIONSare executed. Every mutating verb is refused unless its path starts with one ofpolicy.allowedMutationPaths.policy.excludePathsis honoured always, including whenreadOnlyis off.Every refused operation is reported with its reason by
qa_discover, so you always know what is not covered.Destructive operations are only allowed inside YAML flows, where a human wrote the steps.
Cross-service flows
tests/flows/*.yaml. Real microservice bugs live here, not in single-service tests: each service
passes its own tests while the order id never reaches the notification consumer.
name: order-lifecycle
description: why this scenario matters
role: customer
severity: critical
steps:
- name: create order
service: orders # must match a service name in qa.config.json
method: POST
path: /api/orders
role: customer # optional, overrides the flow role
body: { productId: "{{productId}}" }
expectStatus: [200, 201]
expectBody: { status: Pending } # dot-path -> expected value
capture: { orderId: id } # variable name -> dot-path in the response
waitMs: 0 # pause before the step, for eventual consistency{{var}} interpolation works in path, body, headers and expectBody. Dot-paths understand
array indexes (items[0].status). Flows run sequentially — they mutate shared state. One flow
produces exactly one result: the business scenario either completes or it does not. On failure the
evidence holds the failing step name, the trace of the steps that did succeed, and every captured
variable. waitMs exists for the case where the target service only learns about the change through
a message broker.
Frontend — two layers
Fixed specs (tests/ui/, standalone playwright.config.ts) are run as a child process with
--reporter=json and normalised into results. QA_BASE_URL, QA_LOGIN_PATH and QA_LOGIN
(credentials for the requested role) are passed in as environment variables, so the project also
runs directly in CI. If playwright.config.ts is missing you get a skip with a clear message, not
a crash. Put @critical or @minor in a test title to set its severity.
The three shipped specs assert business outcomes rather than "did the page load": a successful
login, a list that must contain rows (an empty table where data is expected is the classic silent
data-layer failure), and one that fakes a 500 with page.route to prove the UI shows the user an
error instead of hanging on a spinner.
Automatic crawl covers the pages nobody wrote a spec for. It optionally logs in with a role; if
that login fails it returns one critical result and stops immediately, because every later result
would be meaningless without a session. It then BFS-crawls same-origin links up to maxPages,
skipping crawl.ignore prefixes. A route fails on navigation error, HTTP ≥ 400, console errors, an
XHR ≥ 400, or an effectively empty render. Console noise (React DevTools, HMR, React Router future
flags, unused-preload warnings, favicon 404s) is filtered out — without that the output is unusable.
Every failure gets a full-page screenshot whose path lands in the evidence.
Runs, reports and diff
Each run is written to artifactsDir as run-<timestamp>.json plus a readable .html next to it,
with a severity-coloured failure table. Colons and dots in the timestamp are replaced with -
(illegal in Windows filenames); the ids stay lexicographically sortable.
qa_diff compares two runs by stable id and splits the delta:
Bucket | Meaning |
| Passed before, fails now. The only bucket that should block a release. |
| Failed before, passes now. |
| Test did not exist in the baseline and fails now (new endpoint, new page). |
| Already broken before. |
| Was in the baseline, gone now (endpoint or page deleted). |
When no baselineRunId is given, the baseline is the most recent earlier run covering the same
suites — comparing an API-only run against a UI-only run would mark every test as removed and mean
nothing.
Expect the first run to be noisy
This is normal and it is not a bug. The first pass against a real stage environment will report plenty of failures that are configuration, not defects: endpoints needing an id you did not provide, admin-only paths, export jobs, health probes.
Work through it in this order:
Run
qa_discoverand read what was skipped by policy — that is your coverage gap.Run
qa_run_api, then push obvious non-defects intopolicy.excludePaths.Fill
sampleswith real stage ids (orderId,customerId,productId, …) so path and required-query parameters resolve to rows that actually exist. Most 404 noise disappears here.Raise
maxResponseMsif stage is simply slower than production.Re-run until what remains is genuinely interesting.
Keep that run as the baseline. From then on
qa_diff/qa_run_allanswer the only question that matters before a release: did anything that used to work stop working?
Layout
src/
config.ts zod config schema + env: resolution
types.ts TestResult / RunReport / summarize()
discovery/openapi.ts fetch + normalise specs, resolve $ref
auth/session.ts per-role token with cache
api/generator.ts test matrix per operation + safety gate
api/runner.ts bounded-concurrency execution + schema validation
flows/runner.ts cross-service YAML scenarios
ui/crawler.ts automatic Playwright crawl
ui/specs.ts runs Playwright specs, normalises the JSON report
report/store.ts store, diff, render HTML
index.ts MCP tool registration
tests/
flows/*.yaml
ui/ playwright.config.ts + *.spec.tsNotes for whoever extends this
stdio transport: never write to stdout.
console.logcorrupts JSON-RPC and the client disconnects with an opaque error. Every log goes toprocess.stderr(seelog()insrc/index.ts).npm run smokefails if anything non-protocol reaches stdout.ajv/ajv-formatsare CommonJS. UnderNodeNextthe constructable sits on.default, andimport type Ajv from "ajv"is unusable as a type —src/api/runner.tsshows the working pattern.Relative ESM imports need the
.jsextension even from.tssources.Every tool handler is wrapped in
try/catchand returnsisError: truerather than throwing.Every
fetchcarriesAbortSignal.timeout(policy.requestTimeoutMs).Uncompilable response schemas are treated as "no schema", not as an endpoint failure — the defect is in the spec, not in the service.
$refresolution has both a depth cap and a per-branch seen-set; self-referencing DTOs are common in .NET and would otherwise hang the process.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityDmaintenanceA dual-track testing server that combines CLI test execution with Playwright-based browser testing and persistent SQLite logging. It enables automated test pipelines, Git integration, and evidence-based requirement generation to streamline the development lifecycle.
- AlicenseAqualityAmaintenanceAI-powered exploratory QA agent. Explores web apps like a real user — 18 MCP tools for clicking, filling forms, and navigating. Automatically verifies that actions persist (fake deletes, failed edits). Runs 16 detection types including dead links, SEO, accessibility, and performance checks.2292MIT
- Flicense-qualityBmaintenanceEnables automated QA testing by running a pipeline of AI agents that generate test scenarios, architect test layers, write Playwright tests, and review code, all grounded in feature requirements and API contracts.
- AlicenseCqualityBmaintenanceAutomates generation of QA artifacts such as API tests, E2E tests, and documentation exports. It supports REST Assured, Cypress, and Excel/Word document generation.514MIT
Related MCP Connectors
AI QA tester — real browsers scan sites for bugs, SEO, perf, and accessibility issues via chat.
Deterministic axe-core accessibility scans (WCAG 2.1 AA, EN 301 549, PDF/UA) via your account.
Capture screenshots, detect visual regressions between page versions, and analyze with AI.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shahinnr/mcp_qa'
If you have feedback or need assistance with the MCP directory API, please join our Discord server