{
  "markdown": "# AI Quality Gate\n\nMCP Server for AI code quality automation.\n\n[![npm version](https://badge.fury.io/js/ai-quality-gate.svg)](https://www.npmjs.com/package/ai-quality-gate)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n---\n\n## What It Does\n\nAI writes code → calls `quality_fix` → Server fixes what it can → Reports remaining issues to AI.\n\n**Hybrid Approach:**\n\n- **Phase 1:** ESLint + 627 rules + Prettier (~2-8s, always runs)\n- **Phase 2:** SonarQube Server (~30-60s, optional)\n\n**Important: ESLint vs Prettier**\n\n| Tool         | Source                                         | Config                                           |\n| ------------ | ---------------------------------------------- | ------------------------------------------------ |\n| **ESLint**   | Project's config (if exists) or MCP's embedded | `.eslintrc.*` / `eslint.config.*` / MCP embedded |\n| **Prettier** | **Project's own**                              | Project's `prettier.config.mjs`                  |\n\n> ESLint rules are controlled by MCP for consistent quality gates.\n> Prettier uses project's config so formatting matches project preferences.\n\n**Phase 1 Rule Coverage:**\n\n| Plugin            | Rules   | Description                 |\n| ----------------- | ------- | --------------------------- |\n| SonarJS           | 201     | Security, bugs, code smells |\n| Unicorn           | 127     | Modern JS best practices    |\n| ESLint Core       | 108     | JavaScript fundamentals     |\n| TypeScript-ESLint | 99      | TypeScript-specific rules   |\n| RegExp            | 60      | Regex best practices        |\n| Import            | 11      | Import/export rules         |\n| Promise           | 10      | Async/await best practices  |\n| Node.js (n)       | 9       | Node.js specific rules      |\n| Unused Imports    | 2       | Auto-remove unused imports  |\n| **Total**         | **627** |                             |\n\n---\n\n## Installation\n\n### Prerequisites\n\n- **Node.js 18+** on your PATH (`node -v`).\n- **Cursor**, **Antigravity**, **OpenCode** (or another MCP-capable editor) with MCP enabled.\n\nProject root is **auto-detected** when `PROJECT_ROOT` is omitted: the server walks up from the MCP process working directory until it finds `package.json` or `tsconfig.json`. Set `PROJECT_ROOT` in `env` only to analyze a different tree than the inferred root.\n\n---\n\n### MCP configuration (Cursor)\n\nOpen **Settings → Tools & MCP → Edit** (user `mcp.json`). Add **one** server block; the examples below match [`.cursor/mcp.json.example`](.cursor/mcp.json.example) (JSONC with comments — if your editor rejects comments, copy the JSON blocks below only).\n\n**Server name vs tool name:** The key under `mcpServers` (e.g. `\"ai-quality-gate\"`) is only the label for that connection in Cursor. The MCP **tool** your agent calls is always `quality_fix` — that name is fixed by this package and is separate from the server key and from `ai-quality-gate`.\n\n#### A) Recommended: `npx` (no global install)\n\nAlways runs the published package; good for teams and CI-like setups.\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-quality-gate\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ai-quality-gate\"]\n    }\n  }\n}\n```\n\n#### B) Optional: global `npm` install\n\nAfter `npm i -g ai-quality-gate`, the `ai-quality-gate` binary is on your PATH:\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-quality-gate\": {\n      \"command\": \"ai-quality-gate\",\n      \"args\": []\n    }\n  }\n}\n```\n\n#### C) SonarQube (Phase 2)\n\nRequires a running SonarQube instance, `sonar-scanner` available (see [SonarQube Setup](#optional-sonarqube-server-phase-2)), and all three variables below. Phase 1 still runs first.\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-quality-gate\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ai-quality-gate\"],\n      \"env\": {\n        \"SONAR_HOST_URL\": \"http://localhost:9000\",\n        \"SONAR_TOKEN\": \"your_sonar_token\",\n        \"SONAR_PROJECT_KEY\": \"your_project_key\"\n      }\n    }\n  }\n}\n```\n\n#### D) Optional environment variables (any server)\n\nAdd an `\"env\"` object when you need overrides. Merge order for config is **defaults → `.quality-gate.yaml` / `.quality-gate.json` → environment variables**.\n\n| Variable              | When to set                                                                                           |\n| --------------------- | ----------------------------------------------------------------------------------------------------- |\n| `QUALITY_GATE_CONFIG` | Absolute path to a specific `.quality-gate.yaml` or `.quality-gate.json` (skips walking directories). |\n| `PROJECT_ROOT`        | Force project root if auto-detection is wrong for your layout.                                        |\n| `SONAR_HOST_URL`      | SonarQube server URL (with Phase 2).                                                                  |\n| `SONAR_TOKEN`         | SonarQube token (with Phase 2).                                                                       |\n| `SONAR_PROJECT_KEY`   | SonarQube project key (with Phase 2).                                                                 |\n| `SONAR_SCANNER_PATH`  | Full path to `sonar-scanner` if not on `PATH`.                                                        |\n| `PHASE1_TIMEOUT`      | Phase 1 timeout (ms), default `30000`.                                                                |\n| `PHASE2_TIMEOUT`      | Phase 2 timeout (ms), default `300000`.                                                               |\n| `ENABLE_I18N_RULES`   | `true` / `false` — stricter JSX literal checks for i18n projects.                                     |\n\n---\n\n### MCP configuration\n\n#### Cursor, Antigravity, etc..\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-quality-gate\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ai-quality-gate\"]\n    }\n  }\n}\n```\n\n#### (OpenCode)\n\nCreate or edit **OpenCode config** (typically `~/.config/opencode/opencode.json` or project-level config):\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"mcp\": {\n    \"ai-quality-gate\": {\n      \"type\": \"local\",\n      \"enabled\": true,\n      \"command\": [\"npx\", \"-y\", \"ai-quality-gate\"]\n    }\n  }\n}\n```\n\nEnvironment variables can be added under the server config if needed (see [C) SonarQube (Phase 2)](#c-sonarqube-phase-2) above).\n\n---\n\n### Local development (this repository)\n\nTo dogfood or contribute:\n\n1. **`yarn build`** — generates `dist/server.js`.\n2. Point MCP at the built file (absolute paths):\n\n```json\n{\n  \"mcpServers\": {\n    \"ai-quality-gate-dev\": {\n      \"command\": \"node\",\n      \"args\": [\"/ABSOLUTE/PATH/TO/ai-quality-gate/dist/server.js\"]\n    }\n  }\n}\n```\n\n3. Reload MCP. Use `env.PROJECT_ROOT` only if the repo you analyze differs from the inferred root.\n\n---\n\n### 2. Add AI Rule\n\n`Settings` → `Rules and Commands` → `Add Rule`:\n\n```\nAfter every code change, before telling the user \"done\",\nAI must call the quality_fix MCP tool. This is mandatory.\n```\n\n### 3. Use It\n\n```\nAI writes code → calls quality_fix → Fixes errors → \"Done ✅\"\n```\n\n---\n\n## CLI: interactive config (`--setup`)\n\nThe **interactive wizard** creates or updates `.quality-gate.yaml` without hand-editing: it walks you through project root, optional SonarQube (host URL + project key; **token is not saved to disk** — use `SONAR_TOKEN` in your environment), which Phase 1 tools to enable (ESLint, curly-brace / arrow AST fixers, Prettier, JSON validator), timeouts, and i18n rules. The generated file includes a `fixers:` block you can adjust later.\n\nAfter `yarn build` (or install from npm), run from the target project (or any path under it):\n\n```bash\nnode dist/server.js --setup\n```\n\n`PROJECT_ROOT` is inferred when unset (see [MCP configuration](#mcp-configuration-cursor)). Use the same entrypoint as the MCP server (`node dist/server.js` or `npx ai-quality-gate`); only the `--setup` flag switches to wizard mode. Answer prompts in the terminal; on success you get a ready-to-use config next to your project root.\n\n**Other CLI modes:** `--check` (read-only Phase 1), `--fix` (default behavior when using CLI quality run), `--phase1-only`, `--phase2-only` — see [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md).\n\n---\n\n## Optional: SonarQube Server (Phase 2)\n\nConfigure Sonar env in MCP as in **[C) SonarQube (Phase 2)](#c-sonarqube-phase-2)** above, or copy from [`.cursor/mcp.json.example`](.cursor/mcp.json.example). You need **`sonar-scanner`** on your machine for analysis (see below).\n\n### SonarQube Setup\n\n#### Docker (Recommended)\n\n```bash\n# Start SonarQube\ndocker run -d --name sonarqube -p 9000:9000 sonarqube:community\n\n# First login: admin/admin → change password\n# http://localhost:9000\n```\n\n#### Docker Compose\n\n```yaml\n# docker-compose.yml\nversion: '3'\nservices:\n  sonarqube:\n    image: sonarqube:community\n    ports:\n      - '9000:9000'\n    volumes:\n      - sonarqube_data:/opt/sonarqube/data\n      - sonarqube_logs:/opt/sonarqube/logs\n      - sonarqube_extensions:/opt/sonarqube/extensions\n\nvolumes:\n  sonarqube_data:\n  sonarqube_logs:\n  sonarqube_extensions:\n```\n\n```bash\ndocker-compose up -d\n```\n\n### Creating SonarQube Token\n\n1. http://localhost:9000 → Login (admin)\n2. **My Account** → **Security** → **Generate Tokens**\n3. Select token type: **Global Analysis Token**\n4. Copy token → use as `SONAR_TOKEN`\n\n### Installing sonar-scanner\n\n| Platform    | Method       | Command                                    |\n| ----------- | ------------ | ------------------------------------------ |\n| **Windows** | npm (global) | `npm install -g sonarqube-scanner`         |\n| **Windows** | Chocolatey   | `choco install sonar-scanner`              |\n| **macOS**   | npm (global) | `npm install -g sonarqube-scanner`         |\n| **macOS**   | Homebrew     | `brew install sonar-scanner`               |\n| **Linux**   | npm (global) | `npm install -g sonarqube-scanner`         |\n| **Docker**  | Container    | `docker run sonarsource/sonar-scanner-cli` |\n\nFor custom path: `SONAR_SCANNER_PATH` env var\n\n---\n\n## Configuration\n\nOptional files (discovered by walking up from the inferred project root — same algorithm as `package.json` / `tsconfig.json` — or from `PROJECT_ROOT` when set): **`.quality-gate.yaml`** (preferred) or **`.quality-gate.json`**. Same fields as environment variables (camelCase); you may nest Sonar settings under `sonar: { hostUrl, token, projectKey, scannerPath }`.\n\nMerge order: **defaults → config file → environment variables** (ENV wins on conflicts).\n\nSet **`QUALITY_GATE_CONFIG`** to an explicit path to skip discovery.\n\n### Custom rules (`customRules`)\n\nOptional **line-based regex** checks on lintable files (Phase 1). Each match is reported as an issue with `rule` set to `custom:<id>` (and included in `quality_fix` `remaining`). Example:\n\n```yaml\ncustomRules:\n  - id: no-console\n    message: 'Console.log is not allowed'\n    pattern: 'console\\\\.log\\\\('\n    severity: error\n  - id: no-debugger\n    message: 'Debugger statement found'\n    pattern: 'debugger'\n    severity: warning\n```\n\nPatterns use JavaScript `RegExp` source (escape backslashes as in YAML strings). Invalid patterns are skipped at runtime with a log line.\n\n### JSON validator & i18n locale files\n\nWhen **`fixers.jsonValidator`** is enabled and you pass JSON paths that match locale patterns (for example `locales/en.json` / `locales/tr.json`), the tool compares keys across those files.\n\n- **Syntax errors, invalid UTF-8 BOM, etc.** → reported as `issues` and **fail** Phase 1 / `quality_fix` until fixed.\n- **Missing or extra keys between locale files** → collected as **`i18nIssues`** in the validator result and printed as **warnings on stderr** during Phase 1. They do **not** set `passed: false` and do **not** block the gate.\n\nTreat `i18nIssues` as advisory unless you add your own CI check on top.\n\n---\n\n## Environment Variables\n\nAll variables are **optional** unless you use Phase 2, which requires **`SONAR_HOST_URL`**, **`SONAR_TOKEN`**, and **`SONAR_PROJECT_KEY`** together.\n\n| Variable              | Description                                                                                                                  | Example                                |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |\n| `QUALITY_GATE_CONFIG` | Absolute path to a `.quality-gate.yaml` or `.quality-gate.json` file. Skips walking parent directories for config discovery. | `/app/ci/quality-gate.yaml`            |\n| `PROJECT_ROOT`        | Override detected project root. Default: walk up from the process cwd until `package.json` or `tsconfig.json` is found.      | `/Users/me/my-repo`                    |\n| `SONAR_HOST_URL`      | SonarQube server base URL (Phase 2).                                                                                         | `http://localhost:9000`                |\n| `SONAR_TOKEN`         | SonarQube authentication token (Phase 2). Prefer env / secret store; avoid committing.                                       | `sqa_xxx...`                           |\n| `SONAR_PROJECT_KEY`   | SonarQube project key (Phase 2).                                                                                             | `my-project`                           |\n| `SONAR_SCANNER_PATH`  | Full path to the `sonar-scanner` executable if it is not on `PATH`.                                                          | `/opt/sonar-scanner/bin/sonar-scanner` |\n| `PHASE1_TIMEOUT`      | Phase 1 subprocess timeout in milliseconds.                                                                                  | `30000` (default)                      |\n| `PHASE2_TIMEOUT`      | Phase 2 (Sonar) timeout in milliseconds.                                                                                     | `300000` (default)                     |\n| `ENABLE_I18N_RULES`   | Set to `true` to enable ESLint rules that flag raw string literals in JSX (for i18n-heavy apps).                             | `false` (default)                      |\n\n---\n\n## Auto-Fix\n\nPhase 1 automatically fixes these issues:\n\n### ESLint Auto-Fix (~100+ rules)\n\n```typescript\n// var → const/let\nvar x = 1        →  const x = 1\n\n// forEach → for...of (unicorn/no-array-for-each)\narr.forEach(x => f(x))  →  for (const x of arr) f(x)\n\n// Nested ternary → extracted (unicorn/no-nested-ternary)\na ? b : c ? d : e  →  const temp = c ? d : e; a ? b : temp\n\n// Unused imports removed\nimport { unused } from 'x'  →  (removed)\n\n// Type imports (consistent-type-imports)\nimport { Type } from 'x'  →  import type { Type } from 'x'\n\n// Optional chain (prefer-optional-chain)\na && a.b && a.b.c  →  a?.b?.c\n\n// Regex optimization (regexp/*)\n/[0-9]/  →  /\\d/\n```\n\n### AST Auto-Fix\n\n```typescript\n// Remove unnecessary curly braces (single-line if)\nif (x) { return true }  →  if (x) return true\n```\n\n### Prettier Formatting\n\nAfter ESLint fixes, Prettier runs to ensure consistent formatting:\n\n```typescript\n// ESLint removes braces but leaves awkward format:\nif (x) return true\n\n// Prettier fixes to single line:\nif (x) return true\n```\n\n> **Note:** Prettier uses project's config, not MCP's.\n\n**Everything else:** Reported to AI, AI fixes it.\n\n---\n\n## API\n\n### Tool: `quality_fix`\n\n```typescript\n// Input\n{\n  files: string[] // File paths to check\n}\n\n// Output\n{\n  phase: \"local\" | \"server\" | \"complete\",\n  success: boolean,\n  message: string,\n  fixed: {\n    eslint: number,          // ESLint auto-fixes\n    curlyBraces: number,   // AST: single-statement if braces\n    singleLineArrow: number, // AST: arrow body style\n    prettier: number,      // Prettier formatting\n    json: number           // JSON validation passes counted\n  },\n  remaining: Issue[],\n  timing: {\n    phase1: string,\n    phase2?: string,\n    total: string\n  }\n}\n```\n\n---\n\n## Feature Flags\n\n### `ENABLE_I18N_RULES`\n\nFor projects with internationalization (i18n), enable literal string detection:\n\n```json\n{\n  \"env\": {\n    \"ENABLE_I18N_RULES\": \"true\"\n  }\n}\n```\n\nWhen enabled:\n\n```tsx\n// ⚠️ Warning\n<h1>Hello World</h1>\n\n// ✅ OK\n<h1>{t('hello')}</h1>\n```\n\n---\n\n## Troubleshooting\n\n### MCP: `quality_fix` does not appear\n\n1. **Node.js 18+** — run `node -v` and `npx --version`.\n2. **Reload** Cursor after editing `mcp.json` (or use the MCP refresh control).\n3. **JSON** — the file must be valid JSON (no trailing commas). Copy from the [MCP configuration](#mcp-configuration-cursor) section if unsure.\n4. **Global install** — if you use `\"command\": \"ai-quality-gate\"`, run `npm i -g ai-quality-gate` once so the binary exists.\n\n### Windows\n\n**\"npx not found\" error:**\n\n```bash\n# Node.js must be in PATH\n# Check in PowerShell:\nwhere.exe npx\n```\n\n**Permission denied:**\n\n```bash\n# Run PowerShell as Administrator\n```\n\n### macOS / Linux\n\n**\"Permission denied\" error:**\n\n```bash\n# Fix npm global directory\nmkdir ~/.npm-global\nnpm config set prefix '~/.npm-global'\necho 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc\nsource ~/.zshrc\n```\n\n**\"sonar-scanner not found\" error:**\n\n```bash\n# Install via Homebrew\nbrew install sonar-scanner\n\n# Or via npm\nnpm install -g sonarqube-scanner\n```\n\n### SonarQube\n\n**\"Insufficient privileges\" error:**\n\n- SonarQube → **Administration** → **Security** → **Global Permissions**\n- Give **Anyone** group **Browse** and **Execute Analysis** permissions\n\n**\"Project not found\" error:**\n\n- Create project manually for first analysis: **Projects** → **Create Project** → **Manually**\n\n---\n\n## Clone & build (contributors)\n\n```bash\ngit clone https://github.com/mustafacagri/ai-quality-gate.git\ncd ai-quality-gate\nyarn install\nyarn build\n```\n\nUse [Local development (this repository)](#local-development-this-repository) for MCP pointing at `dist/server.js`.\n\n---\n\n## Docs\n\n- [SETUP.md](./SETUP.md) — Local setup (if included in your tree)\n- [AGREEMENTS.md](./docs/AGREEMENTS.md), [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md), etc. — optional; some files may be omitted in minimal clones. **README** + **`.cursor/mcp.json.example`** are enough to run the published package.\n\n---\n\n## Principles\n\n- ✅ 627 ESLint rules (SonarJS, Unicorn, TypeScript-ESLint, etc.)\n- ✅ Prettier integration (uses project's config)\n- ✅ AST-based transforms (no regex)\n- ✅ Verify after each fix\n- ✅ Rollback on error\n- ✅ ESLint config discovery (uses project config if available, otherwise embedded)\n- ✅ Zero workaround\n- ✅ Principal level\n\n---\n\n## License\n\nMIT © [Mustafa Çağrı Güven](https://github.com/mustafacagri)\n\n---\n\n**v0.0.1** — Initial release! MCP `quality_fix`, Phase 1/2 pipeline, CLI, config files, custom rules (see [CHANGELOG](./CHANGELOG.md))\n",
  "bytes": 18632,
  "sha": "50a660dd4201c1b1915e85740e9ad3bdfaec47ea23de11e8b98cbc68bd7d5b29",
  "repo_slug": "mustafacagri/ai-quality-gate",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mustafacagri_ai_quality_gate_ba120f9c/readme"
}