AIQUAA QA Core

by stevenayal

Not rated
GitHub

About

Reusable QA core for MCP servers, providing requirements analysis, traceability, coverage, change planning, secure patching, and GitHub integrations.

Details

Author
stevenayal
Categories
Developer Tools

Setup

Install AIQUAA QA Core in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/stevenayal/aiquaa-mcp-qa-core

Follow the installation instructions in the repository README, then restart your MCP client.

Reusable hexagonal-architecture core shared by AIQUAA's QA MCP servers (aiquaa-playwright-mcp-server,aiquaa-api-quality-mcp-server,aiquaa-performance-mcp-server, and future Hurl/Pact/k6/Selenium/Appium/REST Assured MCPs).

It centralizes the parts of an AIQUAA QA MCP server that have nothing to do with a specific testing tool: requirement normalization, traceability, coverage aggregation, change planning, patch generation, security policies, and adapters for GitHub, AIQUAA, CodeGraph, and Engram. It never imports Playwright, Postman, Newman, JMeter, Hurl, k6, Selenium, or Appium.

The core does: normalize requirements and acceptance criteria; model business rules; build and query a requirement→evidence traceability graph; aggregate coverage from tool-specific evaluators; plan changes (create/extend/modify/keep/deprecate/delete/block) under safety rules; generate/validate/apply unified diffs; scan for secrets and enforce path/write/execution/host policies; talk to GitHub, AIQUAA, CodeGraph, and Engram through ports; and shape MCP tool responses consistently.

The core does not: generate Playwright specs or Gherkin, build Postman collections, run Newman or JMeter, open a browser, interpret locators, compute JTL percentiles, or generate JMX XML. Those stay in the consumer MCP, wired in through theQaToolPlugincontract.

SeeARCHITECTURE.mdfor the layer breakdown andMIGRATION.mdfor the inventory of what moved out ofaiquaa-playwright-mcp-serverand why.

Node.js 20+ required. The package is ESM-only, tree-shakeable, side-effect-free on import, and ships subpath exports so you never need to reach intodist/:

import { createQaCore } from "@aiquaa/mcp-qa-core"; import { CoverageEngine } from "@aiquaa/mcp-qa-core/coverage"; import { TraceabilityEngine } from "@aiquaa/mcp-qa-core/traceability"; import { ChangePlanner } from "@aiquaa/mcp-qa-core/changes"; import { generateUnifiedDiff, PatchValidator } from "@aiquaa/mcp-qa-core/patches"; import { LocalGitRepositoryAdapter } from "@aiquaa/mcp-qa-core/repository"; import { OctokitPullRequestAdapter, GitHubRepositoryAdapter } from "@aiquaa/mcp-qa-core/github"; import { HttpAiquaaAdapter } from "@aiquaa/mcp-qa-core/aiquaa"; import { CodeGraphCliAdapter } from "@aiquaa/mcp-qa-core/codegraph"; import { EngramCliAdapter } from "@aiquaa/mcp-qa-core/memory"; import { SecretScanner, PathPolicy } from "@aiquaa/mcp-qa-core/security"; import { createToolSuccess, toMcpStructuredContent } from "@aiquaa/mcp-qa-core/mcp"; import { createQaCoreTestHarness } from "@aiquaa/mcp-qa-core/testing";
import { createQaCore, createDefaultConfig } from "@aiquaa/mcp-qa-core"; const qaCore = createQaCore({ config: createDefaultConfig() }); const [requirement] = qaCore.requirements.normalize([ { externalId: "REQ-42", title: "Login", description: "User can log in with email and password." }, ]); const context = qaCore.createContext({ operationId: "generate-123", dryRun: true });

Every consumer MCP implementsQaToolPlugin<TInput, TAnalysis, TArtifact>— the seam that keeps tool-specific logic out of the core:

import type { QaToolPlugin, CoverageReport, ChangePlan } from "@aiquaa/mcp-qa-core"; export const examplePlugin: QaToolPlugin<ExampleInput, ExampleAnalysis, ExampleArtifact> = { name: "example", version: "1.0.0", canHandle(input) { return input.type === "example"; }, async analyze(input, context) { return { source: input, findings: [] }; }, async evaluateCoverage(analysis, context): Promise<CoverageReport> { return { items: [], summary: { total: 0, covered: 0, partiallyCovered: 0, uncovered: 0, blocked: 0, outdated: 0, percentage: 0 } }; }, async planChanges(analysis, coverage, context): Promise<ChangePlan> { return { strategy: "keep", changes: [], assumptions: [], warnings: [], blockedReasons: [] }; }, async generateArtifacts() { return []; }, }; const result = await qaCore.runPlugin(examplePlugin, input); // result.analysis, result.coverage, result.changePlan, result.artifacts

SeeMIGRATION.mdfor a full Playwright-shaped example.

The core never decides what "covered" means for a specific tool — it aggregates evaluators you supply:

import { CoverageEngine } from "@aiquaa/mcp-qa-core/coverage"; const engine = new CoverageEngine([myToolSpecificEvaluator]); const report = await engine.evaluate(myContext); // report.summary.percentage, report.items[]
import { TraceabilityEngine } from "@aiquaa/mcp-qa-core/traceability"; const engine = new TraceabilityEngine(); const graph = engine.build({ requirements, scenarios, artifacts, executionResults, evidence }); engine.findUncoveredCriteria(graph, allCriteria); engine.findOrphanArtifacts(graph, allArtifacts); engine.findBrokenLinks(graph, { requirement: new Set(requirementIds) });
import { ChangePlanner } from "@aiquaa/mcp-qa-core/changes"; import { PatchGenerator, PatchValidator, PatchApplier } from "@aiquaa/mcp-qa-core/patches"; const plan = new ChangePlanner().plan({ candidates: [{ targetPath: "tests/login.spec.ts", decision: "create", reason: "covers REQ-42", requirementIds: ["req-42"], businessRuleIds: [], risk: "low" }], existingArtifactPaths: [], requestedScope: ["tests"], }); // plan.strategy, plan.changes[].decision ("create" | "block" | …), plan.blockedReasons

ChangePlannerrefuses duplicate artifacts, blind overwrites (modify/deletewithouthasReadExistingContent: true), out-of-scope paths, unjustified deletes, and changes with no requirement/business-rule evidence — it returns"block"instead.

import { GitHubRepositoryAdapter, OctokitPullRequestAdapter, runPullRequestFlow } from "@aiquaa/mcp-qa-core/github"; const pullRequests = new OctokitPullRequestAdapter({ octokit }); const result = await runPullRequestFlow(pullRequests, { repository: { owner: "aiquaa", repo: "demo" }, baseBranch: "main", branchName: "feat/login-coverage", commitMessage: "test: add login coverage", title: "Add login coverage", body: "Generated by the QA MCP.", files: changePlanFiles, // dryRun and draft both default to true — nothing is written until you opt out. });
import { SecretScanner, PathPolicy, RepositoryWritePolicy } from "@aiquaa/mcp-qa-core/security"; const scanner = new SecretScanner(); scanner.scanText(fileContent); // → SecretFinding[], never the full secret value const pathPolicy = new PathPolicy({ allowedRoots: [projectRoot] }); pathPolicy.assertSafe(candidatePath); // throws UnsafePathError on traversal, .git, node_modules, or escape

RepositoryWritePolicy,ExecutionPolicy, andHostPolicyapply the same "explicit and bounded" default to repository writes, external process execution, and outbound HTTP calls respectively.

import { createQaCoreTestHarness } from "@aiquaa/mcp-qa-core/testing"; const harness = createQaCoreTestHarness({ files: { "src/controller.ts": "..." } }); const result = await harness.runPlugin(myPlugin, input); expect(result.changePlan.strategy).toBe("extend"); expect(harness.pullRequests.commits).toHaveLength(0); // dryRun by default

The harness wiresInMemoryFileSystemAdapter,InMemoryRepositoryAdapter,InMemoryPullRequestAdapter,InMemoryAiquaaAdapter,InMemoryProjectMemoryAdapter, andTestLoggerAdapterinto a realQaCore— no network, no disk, no external process.

import { createToolSuccess, toMcpStructuredContent } from "@aiquaa/mcp-qa-core/mcp"; const response = createToolSuccess({ operationId: context.operationId, summary: "Generated 3 artifacts", data: artifacts }); return toMcpStructuredContent(response, "files"); // { content: [...], isError: false, structuredContent: artifacts }
import { loadConfigFromEnvironment, validateConfig } from "@aiquaa/mcp-qa-core"; const config = loadConfigFromEnvironment(process.env); const validated = validateConfig(config); // Result<QaCoreConfig, ConfigurationError>

Recognized environment variables:GITHUB_TOKEN,GITHUB_API_URL,AIQUAA_API_BASE_URL,AIQUAA_ACCESS_TOKEN,CODEGRAPH_BIN,CODEGRAPH_ALLOWED_ROOTS,ENGRAM_BIN,ENGRAM_PROJECT_PREFIX,QA_CORE_ALLOWED_ROOTS,QA_CORE_MAX_FILE_SIZE,QA_CORE_LOG_LEVEL,QA_CORE_DRY_RUN. Domain and application code never readsprocess.envdirectly — onlyloadConfigFromEnvironmentdoes, and only when you call it.

npm install npm run check # typecheck + lint + test:coverage + build

SeeCONTRIBUTING.mdfor the full workflow andSECURITY.mdfor the vulnerability-reporting process.

This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.

Create crafted UI components inspired by the best 21st.dev design engineers.

Bring agent evaluations, observability, and synthetic test set generation directly into your IDE for free with Galileo's new MCP server

An MCP server to help AI assistants to answer questions and generate AccelByte Extend SDK code more effectively .

MCP server for AI Diagram Maker — generate beautiful software engineering diagrams directly inside Cursor, Claude Desktop, Claude Code, or any MCP-compatible AI agent

ALAPI MCP Tools,Call hundreds of API interfaces via MCP

AI-powered SVG animation generator that transforms static files into animated SVG components using the Allyson platform

MCP server that gives AI assistants on-demand access to 1,500+ amCharts docs, ~300 code examples, and 1000+ class API references.

APIMatic MCP Server is used to validate OpenAPI specifications using APIMatic. The server processes OpenAPI files and returns validation summaries by leveraging APIMatic’s API.

One shared context layer for AI agents and humans — live API specs, DB schemas, and versioned contracts across repos so every agent and teammate works from the same source of truth.

Build and deploy full-stack Next.js apps with 98 tools for React, AWS, and MongoDB

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.