@qcentriq/mcp
Official Model Context Protocol (MCP) server for QCentriq automated test discovery, error diagnostics, script retrieval, and local test execution.
Connect your AI coding assistants (Cursor, Claude Desktop, VS Code Cline / Roo Code, Windsurf, Zed, or Gemini / Antigravity) directly to your QCentriq QA projects to inspect test cases, analyze failure logs, retrieve Playwright test scripts, and validate fixes locally.
⚡ Highlights
- Remote Cloud Discovery & Diagnostics: Instantly query test cases, groups, run logs, failure stack traces, and environment variables via authenticated REST client endpoints.
- Local Playwright Test Execution: Safely execute tests locally with
pytestwithout triggering unwanted cloud runners. Supports headless and headed modes across Chromium, Firefox, and WebKit. - Smart Environment Setup: Probes installed local Python package managers (
uv,poetry,conda, or standardvenv) and generates ready-to-run setup commands (prefersuvfor lightning-fast setup). - Direct Workspace Script Saving: Download test scripts and their helper files into a dedicated
qcentriq_tests/workspace directory (kept apart from your owntests/, so an existingconftest.pyis never overwritten). Before each local run there,qcentriq_run_local_testrefreshes theconftest.pyQCentriq cloud runs use with path traversal protections. - Zero-Leak Redaction: Automatically filters all outgoing tool payloads, masking API keys (
qc_...), bearer tokens, and URL credentials before sending them to the LLM. - Strict Stdio Isolation: Protocol JSON-RPC frames communicate cleanly over
stdout, while all diagnostic logs route tostderr.
🚀 Quick Start
Using npx (No installation needed)
Launch the MCP server directly using npx:
npx -y @qcentriq/mcp@latest --api-key "qc_your_api_key_here"
Or pass your configuration via environment variables:
export QCENTRIQ_API_KEY="qc_your_api_key_here"
export QCENTRIQ_BASE_URL="https://api.qcentriq.com" # Optional, defaults to production
export QCENTRIQ_PROJECT_ID="your-project-uuid" # Optional default project ID
npx -y @qcentriq/mcp@latest
Global Installation
npm install -g @qcentriq/mcp
qcentriq-mcp --api-key "qc_your_api_key_here"
📋 CLI Options & Environment Variables
| CLI Option | Environment Variable | Default | Description |
|---|---|---|---|
-k, --api-key <key> | QCENTRIQ_API_KEY | (Required) | Your QCentriq API key (qc_...). |
-u, --base-url <url> | QCENTRIQ_BASE_URL | https://api.qcentriq.com | Base URL of the QCentriq backend API. |
-p, --project-id <id> | QCENTRIQ_PROJECT_ID | undefined | Optional default project UUID (inferred from API key if omitted). |
-d, --debug | DEBUG or QCENTRIQ_DEBUG | false | Enable verbose debug logging to stderr. |
-h, --help | — | — | Display CLI usage information and flags. |
⚙️ Assistant Configuration Guides
1. Claude Desktop
Add QCentriq to your configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here",
"QCENTRIQ_BASE_URL": "https://api.qcentriq.com",
"QCENTRIQ_PROJECT_ID": "optional-default-project-uuid"
}
}
}
}
2. Cursor IDE
In Cursor, open Settings $\to$ Features $\to$ MCP Servers $\to$ Add New MCP Server, or edit ~/.cursor/mcp.json (or .cursor/mcp.json in your repository root):
{
"mcpServers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here",
"QCENTRIQ_BASE_URL": "https://api.qcentriq.com"
}
}
}
}
3. VS Code (Cline / Roo Code)
In VS Code with the Cline or Roo Code extension, open cline_mcp_settings.json:
{
"mcpServers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here"
},
"disabled": false,
"autoApprove": [
"qcentriq_list_tests",
"qcentriq_get_test",
"qcentriq_get_test_groups",
"qcentriq_get_test_run_logs"
]
}
}
}
4. Windsurf
In ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here"
}
}
}
}
5. Zed
In your Zed settings.json (under experimental.context_servers):
{
"context_servers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here"
}
}
}
}
6. Gemini / Antigravity IDE
In ~/.gemini/config/mcp_config.json (or .agents/mcp_config.json in workspace):
{
"mcpServers": {
"qcentriq": {
"command": "npx",
"args": ["-y", "@qcentriq/mcp@latest"],
"env": {
"QCENTRIQ_API_KEY": "qc_your_api_key_here",
"QCENTRIQ_BASE_URL": "https://api.qcentriq.com"
}
}
}
}
7. Claude Code CLI
Add the QCentriq MCP server using the Claude CLI:
claude mcp add qcentriq -- npx -y @qcentriq/mcp@latest --api-key "qc_your_api_key_here"
🎭 Add Playwright MCP for writing tests (recommended)
Before writing a test plan or script, the assistant is told to explore your app in a real browser with the Playwright MCP server. That way, URLs, labels and selectors come from the pages themselves instead of guesses. QCentriq MCP cannot call Playwright MCP itself, so add it to the same client next to qcentriq:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
With Claude Code: claude mcp add playwright -- npx @playwright/mcp@latest. If Playwright MCP is not connected, the assistant should say so before it writes a plan.
Sites behind HTTP basic auth (common on staging) answer 401 with a blank page until the browser logs in. The assistant is told to notice this and continue on its own. It takes the credentials from your request, or from the environment's BASIC_AUTH_USERNAME / BASIC_AUTH_PASSWORD variables (or the keys that QCENTRIQ_BASIC_AUTH_USERNAME_KEY / QCENTRIQ_BASIC_AUTH_PASSWORD_KEY name). Then it reopens the site with them in the URL, and Chromium remembers them for the rest of the session. It asks you only when the credentials are stored as secrets, because QCentriq never sends secret values to the assistant. To avoid that question, give Playwright MCP the credentials up front by starting it with --config playwright-mcp.json:
{
"browser": {
"contextOptions": {
"httpCredentials": { "username": "staging-user", "password": "staging-password" }
}
}
}
Scripts never contain the credentials. The conftest.py QCentriq ships applies them from BASIC_AUTH_USERNAME / BASIC_AUTH_PASSWORD, which the assistant passes to qcentriq_run_local_test in env_vars for local runs.
🛠️ Available MCP Tools
The QCentriq MCP Server cleanly separates remote cloud discovery/diagnostics (connected via authenticated REST endpoints to /api/v1/mcp-client/) and local client operations (executed purely inside your machine's local workspace):
🌐 Remote Discovery & Diagnostics (Cloud REST Endpoints)
| Tool Name | Description | Key Arguments |
|---|---|---|
qcentriq_list_tests | Discover test cases and test groups with status, priority, and update timestamps. Script availability is highlighted. | project_id (uuid), group_id (uuid), priority ("low"|"medium"|"high"|"critical"), test_type ("web"|"api"|"mobile"), limit (int), offset (int) |
qcentriq_get_test | Retrieve full test case definitions, step descriptions, preconditions, latest execution diagnostics, and error stack traces. | test_case_id (uuid, required), project_id (uuid) |
qcentriq_get_test_groups | Discover and inspect test groups, member test cases, test counts, and script availability. | project_id (uuid), group_id (uuid), limit (int), offset (int) |
qcentriq_download_script | Download Playwright Python test script and its helper files and save them to ./qcentriq_tests/ (the same directory qcentriq_save_script uses). Pass save_to_disk=false to only return the content. | group_id (uuid, required), project_id (uuid), include_fixtures (bool, default true), save_to_disk (bool, default true), destination_dir (string, default "./qcentriq_tests") |
qcentriq_get_environment | Retrieve target environment configuration, base URL (BASE_URL), environment variables, and required secret variable names for local execution. | project_id (uuid), environment_id (uuid), environment_name (string) |
qcentriq_get_test_run_logs | Fetch execution history, logs, stdout/stderr, and stack traces across single-case and suite runs. | test_case_id (uuid, required), project_id (uuid), run_id (uuid), status ("failed"|"passed"|"error"), latest_only (bool), from_date (ISO date), to_date (ISO date), limit (int), offset (int) |
✍️ Authoring (Cloud REST Endpoints, writes require test:write)
The intended order is: qcentriq_get_authoring_guide and qcentriq_get_environment, then explore the app with Playwright MCP, then qcentriq_create_plan, then write the script, run it with qcentriq_run_local_test until it passes, and upload it with qcentriq_save_group_script. The server sends this order to the assistant as its MCP instructions.
Both write tools send to QCentriq as soon as they are called; your MCP client's own tool-approval prompt is the check before an upload (see Security & Privacy).
| Tool Name | Description | Key Arguments |
|---|---|---|
qcentriq_get_authoring_guide | Fetch the contract for plans and scripts: the TaskPlan JSON schema, the ${VAR} environment-variable convention, the @allure.id rules, and the available conftest fixtures. Read-only. | — |
qcentriq_create_plan | Create test groups and test cases from an authored plan. Returns one UUID per created test case. A case whose flow failed in the browser can be created with status: "blocked" and an evidence block_reason; QCentriq re-validates it live and keeps it blocked only if it sees the same failure (block_source shows client until then). Writes. | plan (object, required), project_id (uuid) |
qcentriq_save_group_script | Validate and store a test script for a group, replacing the existing one. Every unblocked case in the group must appear exactly once as @allure.id('<case_id>'); blocked cases may be left out. Only uploads a script that passed qcentriq_run_local_test with this exact content (see Local pass before upload). Checked against the version from the last download or save of the group in this session, so someone else's newer edit is refused as a conflict instead of overwritten. Writes. | group_id (uuid, required), content (string, required), project_id (uuid), filename (string), fixtures (array) |
qcentriq_update_test_case | Edit an existing test case (title, description, priority, preconditions, steps, expected result, target URL) instead of creating a duplicate. Requires last_updated_at from qcentriq_get_test; a newer edit by someone else is refused as a conflict. Reports script_stale when the change means the group script needs updating. Blocked status is not editable. Writes. | test_case_id (uuid, required), expected_last_updated_at (string, required), plus the fields to change, project_id (uuid) |
qcentriq_recheck_blocked_case | Ask QCentriq to re-validate a blocked test case against the live site. QCentriq's own agent decides the verdict: active unblocks the case and adds it to the group script (in a group whose script you wrote, you add the test yourself), blocked refreshes block_reason. The caller cannot set the verdict. Can take several minutes (client timeout 7 min). Writes. | test_case_id (uuid, required), project_id (uuid) |
💻 Local Client Tools (Executed in Your Local Workspace)
| Tool Name | Description | Key Arguments |
|---|---|---|
qcentriq_get_setup_instructions | Detect which Python package managers (uv, poetry, conda, venv) are installed on the local system and return step-by-step commands to create a virtual environment matching the QCentriq runner container. If none are installed, the steps start by installing uv. (Read-only instructions, never runs commands). | preferred_manager ("uv"|"poetry"|"conda"|"venv"), working_dir (string), env_name (string, default "qcentriq-tests"), python_version (string, default "3.12"), playwright_version (string, default "1.56.0") |
qcentriq_save_script | Save downloaded test scripts and fixtures directly into the local workspace (defaults to ./qcentriq_tests/) with path traversal guards. | file_name (string, required), content (string, required), conftest_content (string), destination_dir (string, default "./qcentriq_tests") |
qcentriq_run_local_test | Run the test locally via pytest. Captures stdout, stderr, execution duration, and exit codes without triggering cloud runners. A whole-file pass qualifies that exact script for qcentriq_save_group_script. If no Python package manager is installed, it tells you to install uv first. | file_path (string, required), test_name (string), headless (bool, default true), browser ("chromium"|"firefox"|"webkit", default "chromium"), base_url (url), env_vars (record), extra_args (array), timeout_seconds (int, default 60), working_dir (string) |
🔄 End-to-End AI Self-Healing Workflow
Here is how an AI assistant (e.g. Cursor or Claude) uses @qcentriq/mcp to diagnose and fix a failing test:
sequenceDiagram
autonumber
actor User
participant AI as AI Assistant
participant MCP as QCentriq MCP Server
participant API as QCentriq Cloud API
participant Local as Local Workspace & Subprocess
User->>AI: "Fix the failing login test in QCentriq"
AI->>MCP: qcentriq_list_tests(priority="high")
MCP->>API: GET /api/v1/mcp-client/tests
API-->>MCP: Test cases metadata
MCP-->>AI: List of tests
AI->>MCP: qcentriq_get_test_run_logs(test_case_id="...")
MCP->>API: GET /api/v1/mcp-client/tests/{id}/run-logs
API-->>MCP: Failure trace (e.g. SelectorTimeoutError)
MCP-->>AI: Error diagnostics & stack trace
AI->>MCP: qcentriq_get_setup_instructions()
MCP-->>AI: Recommended setup commands (uv venv, uv pip install ...)
AI->>MCP: qcentriq_download_script(group_id="...")
MCP->>API: GET /api/v1/mcp-client/groups/{id}/script
API-->>MCP: Script & helper files
MCP->>Local: Write qcentriq_tests/test_login.py
MCP-->>AI: File paths confirmed
AI->>Local: Inspect and update selector in test_login.py
AI->>MCP: qcentriq_run_local_test(file_path="qcentriq_tests/test_login.py", headless=false)
MCP->>Local: Run pytest with Playwright
Local-->>MCP: Test result (PASSED)
MCP-->>AI: PASSED (exit code 0, 1.42s)
AI->>User: "Fixed selector in qcentriq_tests/test_login.py and verified locally!"
🔒 Security & Privacy
- Safe Network Boundary: The client MCP server connects exclusively to
${baseUrl}/api/v1/mcp-client/using HTTPS. Discovery and diagnostics tools only read. The authoring toolsqcentriq_create_plan,qcentriq_update_test_case,qcentriq_save_group_scriptandqcentriq_recheck_blocked_casewrite to your project (creating and editing test groups/cases, replacing a group's script, and unblocking a case when QCentriq's live recheck confirms it works), and the backend rejects them unless the API key carries thetest:writescope. - Local Pass Before Upload:
qcentriq_save_group_scriptrefuses a script unless that exact content passedqcentriq_run_local_testin the current server session, as a whole file: notest_name, node id, or-k/-m/--deselect/--lf-style filters, and at least one test passed (not all skipped). Each companion file must match the file that sat next to the script during that run and not have changed since. Passing runs are kept in memory, so after a restart the script has to be run again. If no Python package manager is installed, the refusal says to installuvfirst (recommended), then useqcentriq_get_setup_instructions. - Client-Side Control: Test executions, script modifications, and environment setups happen locally on your machine. No local code or files are uploaded without your knowledge.
- Zero-Leak Redaction: The server actively scans and redacts API keys (
qc_...), bearer tokens, and embedded basic-auth credentials before returning data to the LLM. - Filesystem Security: Path traversal attacks (e.g.
../../etc/passwd) are blocked when writing test scripts and fixtures to disk. - Stdio Integrity: All server diagnostic logs are strictly routed to
stderr. Standard output (stdout) is reserved purely for JSON-RPC 2.0 communication.
💻 Local Development
# Clone the repository
git clone https://github.com/qcentriq/qcentriq.git
cd packages/qcentriq-mcp
# Install dependencies
npm install
# Run typecheck
npm run typecheck
# Run test suite
npm test
# Build production bundle with tsup
npm run build
# Run local development server with live reload
QCENTRIQ_API_KEY="qc_your_key" QCENTRIQ_BASE_URL="http://localhost:8787" npm run dev
📄 License
Apache-2.0 © QCentriq