Skip to main content
Glama

An MCP server that audits a finished web project in a real browser and writes a report another AI can fix code from. It opens the site with Playwright, crawls its pages, clicks the buttons, watches the console and the network, measures layout at several screen widths, runs axe-core for accessibility, checks SEO, images, fonts, performance and basic security, and gives every problem a stable ID, a CSS selector, evidence and a screenshot.

Run it again after the fix and it tells you what was fixed, what is new and what is still there.

Tested on Windows and Python 3.14. Other operating systems and Python versions have not been tested.

A real browser

Chromium via Playwright: real clicks, real layout, real network. Nothing is guessed from the source code.

Made for a fix loop

current.json with one record per problem: rule, page, selector or URL, evidence and a fingerprint that stays the same between runs.

Evidence, not opinions

Every finding says what was measured. Critical findings and warnings come with a screenshot, the element outlined in red.

Prioritized issues

Findings are grouped by cause: one root cause, its related issues, affected pages, impact 1-10 and a fix. Inferred links are marked as likely.

Regression view

Each run is compared with the previous one: ✅ Fixed, 🔴 New, ⚠️ Unchanged.

Safe by design

Read-only for your project, isolated browser context, navigation to other domains blocked, only passive security checks.

Installation

You need Python 3.10+ and an internet connection (Chromium is about 150 MB).

# 1. Create an environment and install straight from GitHub
python -m venv codecheck-env
codecheck-env/Scripts/pip install git+https://github.com/aleks-fw/CodeCheck-MCP.git      # Windows
# codecheck-env/bin/pip install git+https://github.com/aleks-fw/CodeCheck-MCP.git        # macOS / Linux

# 2. Download the browser for Playwright (once)
codecheck-env/Scripts/python -m playwright install chromium

Connect to Claude Code

claude mcp add --scope user codecheck -- "<path>/codecheck-env/Scripts/codecheck-mcp"

Connect to other clients (Claude Desktop, Cursor, ...)

{
  "mcpServers": {
    "codecheck": {
      "command": "<path>/codecheck-env/Scripts/codecheck-mcp",
      "env": { "CODECHECK_REPORTS_DIR": "<where reports go>" }
    }
  }
}

<path> is the absolute path to the folder where you created the environment. CODECHECK_REPORTS_DIR is optional (default ~/codecheck-reports). Restart the client and codecheck appears in its MCP list.

If you are an AI agent

Install by following llms-install.md.

Related MCP server: Vibetest Use

The fix loop: Build → Audit → Fix → Re-audit

  1. Build the site (or start it locally).

  2. Audit. Ask the agent: "Run audit_project on http://localhost:5173 with criticalSelectors ["#checkout"]". You get counts by severity, the critical findings, the top prioritized issue groups and the paths to report.md and current.json.

  3. Fix. "Read current.json and fix the critical findings and warnings. Use the selector, url and evidence of each finding to locate the code." Each finding names the rule, the page, the element or resource and what was observed, so the agent does not have to reproduce the bug first.

  4. Re-audit. Run audit_project again with the same url. The answer starts with Since the previous run: ✅ Fixed 3 · 🔴 New 0 · ⚠️ Unchanged 12; repeat until nothing critical is left.

A finding only counts as fixed if the new run checked the same category, page and viewport; otherwise it is listed as "not rechecked", so a narrower run never reports false fixes.

Tools

Tool

Parameters

What it does

audit_project

url, maxPages=10, viewports=[375, 768, 1280], checks=all, criticalSelectors=[], outputDir

Full audit for the fix loop, see below

compare_reports

previous, current (paths to JSON reports)

Fixed / New / Unchanged between any two audit_project reports

full_qa

target, max_pages=10

Quick QA with the checks below, report in Russian

test_interactions

target, max_pages

Dead buttons, disabled controls that react, covered buttons, forms, double submit, broken anchors

test_layout

target, max_pages, widths=[320, 375, 768, 1024, 1440]

Overlapping and clipped text, horizontal scroll, contrast (also on images), tap targets under 44 px

test_fonts

target, max_pages

Font families, outlier fonts, failed web fonts, size sprawl, heading hierarchy

test_images

target, max_pages

Broken, stretched, blurry, heavy images, missing alt

quick_security

target, max_pages=3

Secrets in files and git history, .env in git, headers, cookies, mixed content

url / target is a URL or a path to a project folder or file; for a folder a temporary local server is started.

audit_project

Parameter

Default

Meaning

url

required

Site URL or project folder / file

maxPages

10

Pages to crawl, same origin only

viewports

[375, 768, 1280]

Screen widths in px (heights 812, 1024, 800)

checks

all

Any of interaction, layout, images, fonts, console, accessibility, seo, performance, security, network

criticalSelectors

[]

Selectors of key actions (e.g. #checkout); if one does nothing on click, the finding is critical

outputDir

<CODECHECK_REPORTS_DIR>/<project>

Where current.json, previous.json, report.md and screenshots/ go

Example call:

{
  "url": "http://127.0.0.1:8765/",
  "criticalSelectors": ["#checkout"],
  "viewports": [375, 768, 1280]
}

Answer (real run on examples/demo-shop with criticalSelectors: ["#checkout", "#place-order"], second run after adding a missing <title>):

CodeCheck audit of http://127.0.0.1:8765/: 9 page(s), viewports 375x812, 768x1024, 1280x800.
Critical: 8 · Warnings: 5 · Notices: 31

Critical:
- CC-001 `interaction/no-effect` on /buttons.html: Clicking #checkout does nothing
- CC-002 `interaction/action-request-failed` on /cart.html: Clicking #place-order sends POST /api/order, which answers HTTP 500
- CC-003 `interaction/action-request-failed` on /checkout.html: Clicking #place-order sends POST /api/order, which answers HTTP 500
- CC-004 `console/uncaught-exception` on /errors.html: Uncaught exception: ReferenceError: cartItems is not defined
- CC-005 `accessibility/image-alt` on /media.html: Images must have alternative text
- CC-006 `network/api-5xx` on /api.html: API request returned HTTP 500
- CC-007 `network/api-5xx` on /checkout.html: API request returned HTTP 500
- CC-008 `network/script-failed` on /media.html: JavaScript file did not load

Top issues (5 of 17 groups):
- G-01 🔴 CRITICAL · impact 10/10 · API request returned HTTP 500 (/api/order) · pages: /cart.html, /checkout.html · 3 related
- G-02 🔴 CRITICAL · impact 10/10 · Clicking #checkout does nothing · pages: /buttons.html
- G-03 🔴 CRITICAL · impact 9/10 · Uncaught exception: ReferenceError: cartItems is not defined · pages: /errors.html
- G-04 🔴 CRITICAL · impact 9/10 · API request returned HTTP 500 (/api/orders) · pages: /api.html
- G-05 🔴 CRITICAL · impact 9/10 · JavaScript file did not load (/js/missing.js) · pages: /media.html

Since the previous run: ✅ Fixed 1 · 🔴 New 0 · ⚠️ Unchanged 44
Fixed:
  CC-013 `seo/missing-title` on `/notitle.html`: Page has no title

Report: .../report.md
JSON: .../current.json
Screenshots: .../screenshots

The top group in the same report.md:

## Prioritized Issues

### 🔴 CRITICAL — API request returned HTTP 500 (/api/order)

- **Impact:** 10/10 (severity 8, breaks a function or exposes data +1, on several pages +1,
  key action (criticalSelectors) +1, causes other issues +1)
- **Category:** functionality
- **Affected pages:** `/cart.html`, `/checkout.html`
- **Root cause:** GET http://127.0.0.1:8765/api/order answered HTTP 500 on /checkout.html. (CC-007)
- **Related issues:**
  - CC-002 `interaction/action-request-failed` on `/cart.html`: Clicking #place-order sends POST /api/order,
    which answers HTTP 500 (confirmed: the click sends a request to the same failing endpoint /api/order)
  - CC-003 `interaction/action-request-failed` on `/checkout.html`: Clicking #place-order sends POST /api/order,
    which answers HTTP 500 (confirmed: the click sends a request to the same failing endpoint /api/order)
  - CC-010 `console/error` on `/checkout.html`: console.error: Could not load the order summary: GET /api/order
    returned 500 (confirmed: the error text mentions /api/order)
- **Recommendation:** The API endpoint in evidence fails on the server: check its server logs, fix the handler,
  and make the page show an error state when the request fails.
- **Evidence:** screenshots: [screenshots/CC-002.png](screenshots/CC-002.png), ... · urls:
  `http://127.0.0.1:8765/api/order` · selectors: `#place-order` · requests:
  `POST http://127.0.0.1:8765/api/order → 500`, `GET http://127.0.0.1:8765/api/order → 500` · console:
  `Could not load the order summary: GET /api/order returned 500`

Below it come the Summary, every finding by severity and category (with its own screenshot and evidence), the list of tested pages and one recommendation per rule that was found.

Prioritized Issues

After all checks, findings are merged into groups, one per cause, and sorted by severity, then impact, then the number of affected pages. Links between findings come only from the findings themselves:

Link

Based on

Marked

The same problem on several pages

same resource URL, or same rule and selector, or same message

same group

A failing request and a click that sends a request to the same endpoint

same URL path

confirmed

A failing request and a console error that names its URL

the URL in the error text

confirmed

A heavy file and the page weight

the file is in the page's largest downloads

confirmed

A missing script and "is not defined" errors or dead buttons on the page

same page

likely

An uncaught exception and a dead button on the page

same page

likely

A failing request and a console error about a request that does not name the URL

same page

likely

A missing stylesheet and layout findings; a slow request and a slow load

same page

likely

If every link of a group is confirmed, the report says Root cause; if any link is inferred, it says Likely root cause. Console errors are recorded while the page loads, before the clicks, so they are never linked to requests sent by a click.

Each group has:

  • severity: CRITICAL (a critical finding), HIGH (a warning about functionality or security), MEDIUM (another warning), LOW (notices only);

  • category: functionality, responsive, performance, accessibility, security, visual or other;

  • impact 1-10: 8 / 5 / 2 for critical / warning / notice, +1 if it breaks a function or exposes data, +1 on several pages or +2 on most pages, +1 for a key action from criticalSelectors, +1 if it causes 2+ other issues; the parts are listed next to the number;

  • affected pages, root cause, related issues (each with the reason of the link), recommendation and evidence (screenshots, URLs, selectors, requests with status, console text).

In current.json the groups are under groups:

{
  "id": "G-01", "title": "API request returned HTTP 500 (/api/order)", "severity": "CRITICAL",
  "category": "functionality", "impact": 10, "impactBasis": {"severity": 8, "on several pages": 1, "...": 1},
  "affectedPages": ["/cart.html", "/checkout.html"],
  "rootCause": {"text": "GET http://127.0.0.1:8765/api/order answered HTTP 500 on /checkout.html.",
                "confirmed": true, "finding": "CC-007", "rule": "network/api-5xx"},
  "relatedIssues": [{"finding": "CC-002", "rule": "interaction/action-request-failed", "page": "/cart.html",
                     "message": "...", "confirmed": true,
                     "link": "the click sends a request to the same failing endpoint /api/order"}],
  "recommendation": "...", "evidence": {"screenshots": [], "urls": [], "selectors": [], "requests": [], "console": []},
  "findings": ["CC-002", "CC-003", "CC-007", "CC-010"]
}

Finding format (current.json)

interface Finding {
  id: string;           // CC-001, CC-002... numbered within the run
  fingerprint: string;  // stable hash of rule + page + (selector or url) for comparing runs
  severity: "critical" | "warning" | "notice";
  category: "interaction" | "layout" | "images" | "fonts" | "console"
          | "accessibility" | "seo" | "performance" | "security" | "network";
  rule: string;         // e.g. "seo/missing-title"
  page: string;         // e.g. "/checkout"
  message: string;      // short description
  details: string;      // what exactly was observed
  selector?: string;    // shortest unique CSS selector
  url?: string;         // for resources and requests
  viewport?: string;    // e.g. "375x812"
  screenshot?: string;  // relative path, critical and warning only
  evidence?: Record<string, unknown>;  // status, size, duration, stack...
}

current.json also holds the run metadata (tool, version, project, url, date, pages, viewports, checks, errors, summary), the groups described above and, from the second run on, a comparison block with the fingerprints of fixed, new and unchanged findings.

What audit_project checks

Category

Rules (severity)

console

uncaught exception (critical), unhandled promise rejection (warning), console.error (warning); stack and source file:line, repeats counted

network

API 5xx (critical), API 4xx (warning, except 401/403 on a login page), JS/CSS failed (critical), image/font failed (warning), request failed (warning), request over 1 s / 3 s (notice / warning)

seo

missing or empty title, missing meta description, missing lang, no <h1> (warning); several <h1>, skipped heading levels, no canonical, no favicon, no Open Graph, no robots.txt / sitemap.xml (notice)

images

image did not load, missing alt (warning); file over 200 KB / 1 MB (notice / warning); natural size over 2× the displayed size (notice)

accessibility

axe-core WCAG 2.x A/AA rules (critical / serious / moderate+minor → critical / warning / notice); onclick elements unreachable by keyboard, no visible focus on Tab (warning)

layout

horizontal scroll with the deepest element past the edge (warning), text clipped by overflow: hidden (notice), tap targets under 24×24 px at 375 px (notice); every viewport

fonts

@font-face font failed to load (warning), text shown in a fallback because the declared font never loaded (notice)

performance

load over 3 s, LCP over 2.5 / 4 s, CLS over 0.1 / 0.25, page over 3 MB, over 100 requests, JS file over 500 KB, CSS file over 150 KB; thresholds in thresholds.py

interaction

clicks up to 20 buttons, href="#" / javascript: links and role="button" per page on a fresh load and watches 2 s for navigation, URL change, requests, DOM changes, dialogs, new tabs; skips logout / delete; critical for criticalSelectors. If the click works but the request it sends fails, interaction/action-request-failed (critical for 5xx, warning for 4xx; 401/403 and 4xx from an empty form are ignored). A critical selector that was never clicked is reported too: critical if it matched no element on any page, warning if it was hidden, invalid, destructive or past the click limit

security

plain HTTP (not localhost), mixed content (warning); no CSP, no nosniff, no HSTS (notice); cookies without Secure or session cookies without HttpOnly (warning); public source maps (notice)

If axe and another check find the same thing (for example a missing alt or lang), it is reported once.

Try it on the demo shop

examples/demo-shop is a small site with deliberate bugs (script errors, a broken image and script, APIs that answer 500, horizontal scroll on phones, a dead checkout button, "Place order" buttons whose request fails, a page without a title) and a clean home page.

python examples/demo-shop/serve.py 8765
# then ask your agent: run audit_project on http://127.0.0.1:8765/ with criticalSelectors ["#checkout", "#place-order"]

Architecture

codecheck_mcp/
  server.py                 MCP tools
  browser.py                Playwright launch, local server for folders, external-domain blocking
  checks/                   checks of the quick tools (full_qa, test_*)
  audit/
    runner.py               audit_project: crawl, run checks per viewport, merge duplicates, write reports
    thresholds.py           every threshold in one place
    core/                   finding, fingerprint, selector, screenshot, crawler, session (events per page)
    checks/                 one module per category; each has run(page, ctx) -> list[Finding]
    report/                 json_report, markdown, diff, priority (grouping)
  vendor/axe.min.js         axe-core 4.13.0, unmodified (MPL-2.0)

Every page is loaded once per viewport; console and network events are recorded before the page starts loading, then each check reads the same page. Checks are registered in audit/checks/__init__.py.

Safety of the server itself

  • Read-only: the project under test is never modified.

  • Pages open in an isolated browser context, without your cookies or sessions.

  • Navigation to other domains is blocked; audit_project does not fill in or submit forms with data and skips buttons that look like logout or delete.

  • Security checks are passive: they read headers, cookies and public files, and never attack the site.

  • Secrets found by quick_security are masked in reports.

  • Test only your own projects, or sites you have the owner's permission to test.

Known limitations

  • A full audit_project takes about 30 s for a small site; pages with many dead buttons take longer (up to 2 s per click). Lower maxPages or narrow checks for large sites.

  • Console, network, SEO, images, fonts, accessibility, performance and security run at the widest viewport only; layout runs at every viewport.

  • Server headers and cookies are not checked for a local folder (they come from the temporary server, not from your project).

  • Only the onclick attribute is seen, not listeners added with addEventListener.

  • Sizes are transferred bytes: a local folder is served without compression, so real hosting may be lighter.

  • The comparison is with the previous run in the same output folder only.

Roadmap

  • Optional session setup (cookies or a login script) to audit pages behind a login.

  • Check console and network at every viewport.

  • A max duration limit for very large sites.

  • Test on macOS and Linux.

Development

pip install -e ".[dev]"
python -m playwright install chromium
pytest tests -q
ruff check codecheck_mcp tests
mypy codecheck_mcp

The tests use pages with deliberate bugs, clean pages that must produce no findings, and regressions found on real sites. See CONTRIBUTING.md.

License

MIT, see LICENSE. codecheck_mcp/vendor/axe.min.js is axe-core by Deque Systems, MPL-2.0, see codecheck_mcp/vendor.

Available Tools

8 tools
audit_projectAudit ProjectA

Audit a web project for an automated fix loop (Build → Audit → Fix → Re-audit). url: site URL or path to the project folder/file. maxPages: same-origin pages to crawl. viewports: widths in px (default 375, 768, 1280). checks: categories (default all). criticalSelectors: selectors of key actions; a dead one is critical. outputDir: where current.json, report.md and screenshots/ go (default: a folder per project in CODECHECK_REPORTS_DIR). Returns counts by severity, the critical findings and paths to the files.

Inputs: url (required), checks, maxPages, outputDir, +2 more. Returns: result

compare_reportsCompare ReportsA

Compare two audit_project JSON reports (paths to current.json / previous.json files) by fingerprint. Returns Fixed, New, Unchanged and findings the newer run did not recheck.

Inputs: current (required), previous (required). Returns: result

full_qaFull QaB

Полный QA: кнопки, вёрстка (5 ширин экрана), шрифты, изображения и лёгкая проверка безопасности.

Inputs: target (required), max_pages. Returns: result

quick_securityQuick SecurityC

Лёгкая безопасность: секреты в файлах и истории git, .env в git, заголовки, cookies, mixed content.

Inputs: target (required), max_pages. Returns: result

test_fontsTest FontsD

Шрифты: единообразие семейств и размеров, незагрузившиеся веб-шрифты, иерархия заголовков.

Inputs: target (required), max_pages. Returns: result

test_imagesTest ImagesC

Изображения (только измеримое): битые, искажённые, мыльные, тяжёлые, без alt.

Inputs: target (required), max_pages. Returns: result

test_interactionsTest InteractionsC

Кнопки и ссылки: мёртвые кнопки, отключённые, что всё равно реагируют, перекрытые, формы, битые якоря.

Inputs: target (required), max_pages. Returns: result

test_layoutTest LayoutC

Вёрстка: наложение текста, обрезанный текст, горизонтальный скролл, контраст, мелкие зоны нажатия. widths: ширины экрана в px (по умолчанию 320, 375, 768, 1024, 1440).

Inputs: target (required), widths, max_pages. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    C2.7/5.0

    Scored across 8 tools

    Disambiguation2/5

    full_qa overlaps heavily with the individual test_* tools and quick_security, since it bundles the same checks. audit_project also subsumes most of these checks, making it unclear when to use the broad tools versus the granular ones.

    Naming Consistency3/5

    The test_* tools follow a consistent pattern, but full_qa, quick_security, audit_project, and compare_reports break it. The mix of adjective_noun, verb_noun, and test_* styles creates a somewhat inconsistent naming scheme.

    Tool Count4/5

    8 tools is a reasonable count for a QA/audit server. However, full_qa and audit_project duplicate much of the test_* suite, so the same functionality could be consolidated slightly.

    Completeness4/5

    The set covers interactions, layout, fonts, images, security, full audits, and report comparison, forming a solid QA workflow. Minor gaps like dedicated performance or SEO checks exist, but they are not essential to the stated purpose.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      Not graded
      maintenance
      Provides comprehensive website validation across performance, accessibility, SEO, and security dimensions using multiple testing services including WebPageTest, Google PageSpeed Insights, Axe DevTools, Mozilla Observatory, and SSL Labs. Enables automated website health assessments through browser automation and API integrations.
      2
      12
      3 npm
      1
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Browser-based QA testing for AI-built software. Agents open real browsers (via Selenium), navigate pages, fill forms, click buttons, and report findings. Two modes: targeted tests (30-90s) and full-site discovery scans (3-15min).
      -