@buyhatke-dev/nitpick-mcp
v0.2.0
Published
Nitpick Testing MCP — agent-agnostic exploratory UI reviewer (host-is-brain, driver abstraction, persistent .qa/ memory)
Readme
Nitpick Testing MCP
Agent-agnostic exploratory UI reviewer, delivered as an MCP server. It reviews an app and informs — it never changes application code.
Design: host-is-brain (no embedded LLM — your coding agent drives), composable tools,
driver abstraction (Maestro for mobile, Playwright for web — both live), and persistent
in-repo .qa/ memory with a reconciled findings ledger.
Install & build
cd nitpick-mcp
npm install
npm run buildRequires: Node 18+. Prerequisites depend on the driver — run the doctor tool to check:
- Maestro (mobile): just
adbon PATH + an attached Android device — no Android Studio. A real phone over USB (Developer options → USB debugging → accept the RSA prompt) is the lightest path. ThemaestroCLI is optional — onlyrun_flow(replaying saved flows) uses it; every interactive tool drives the device throughadbdirectly, so it never blocks readiness. - Playwright (web): the
playwrightpackage + a chromium browser —doctor { install: true }installs both automatically (they're self-contained). System-level pieces (adb, the Maestro CLI, Android SDK/AVD) are detected and reported with fix guidance, never silently installed.
start_session runs doctor as a preflight and reports readiness in its envelope, so you know
what's missing before any action fails.
Register with an MCP client
Install it first (see INSTALL.md for git/tarball/source options), then register the
installed nitpick-mcp binary. Claude Code:
claude mcp add nitpick -- nitpick-mcpOr add to any MCP client config:
{ "mcpServers": { "nitpick": { "command": "nitpick-mcp" } } }Don't register
npx <git-url>or a.tgzas the command — it re-installs on every launch and can exceed the client's connect timeout. Install once, then point the client at the installed bin.
Use
start_sessionwith aprojectPath(imported: code + UI), aurl(web, link-only: UI), or anappId(mobile black-box: installed app, UI-only;.qa/stored under~/.qa-mcp/projects/<slug>/). It auto-detects platform/driver/source, creates.qa/, and returns a guided envelope telling the agent whether to map or review next, with the methodology inline.- First run → follow
qa_map(index the app intomap.md+flows/, draftbrief.md). - Later runs → follow
qa_review(explore/brute-test, record findings). The agent readsqa://findingsfirst and reconciles; the server maintains the ledger and regeneratesfindings.mdwith a since-last-run diff.
Surface
| Kind | Names |
|---|---|
| Session & auth | start_session, doctor, login, save_auth |
| Perception & interaction | capture, tap, long_press, scroll, input, press, hover, focus, scroll_to, select_option, set_checked, drag, upload_file |
| Navigation & tabs | navigate, open_tab, list_tabs, switch_tab, close_tab, current_page |
| Sync & retrieval | wait, observe, evaluate, inspect_ui, extract_ui |
| State & journeys | save_ui_state, compare_ui_state, run_flow, save_flow |
| UX & memory | audit_ui, list_findings, record_finding, update_brief, update_map, export_report, export_data |
| Resources | qa://config, qa://brief, qa://map, qa://flows, qa://flows/{name}, qa://findings, qa://review-guide, qa://help |
| Prompts | qa_map, qa_review, help |
v0.2.0 — general-purpose UI exploration: bounded/scoped capture with rich element state,
a multi-page registry (tabs, popups, frames, redirects, cross-domain workspaces), complete
interactions with structured results, schema-free inspect_ui/extract_ui, UI-state diffs,
versioned journeys with assertions + retained failure evidence, deterministic audit_ui, and
PDF/HTML/JSON/CSV artifacts with verified paths. All new args are optional; existing calls and
saved .qa/ projects stay compatible, and ordinary traversal no longer needs evaluate.
Web-only tools return a clear capability error under the Maestro (mobile) driver.
capture() returns the screenshot inline as an image (Set-of-Mark: each element outlined
with its id, e.g. e13) alongside { screenshot, elements[labeled], errors, size }. Act by
label or id, not coordinates: tap("Continue") / tap("e13") and the driver resolves it.
Toggle with capture({ annotate: false }) / capture({ image: false }). (Set-of-Mark overlay is
web-only today; inline image works for both drivers.)
Memory layout (.qa/)
config.yaml brief.md map.md flows/ findings.md findings.json
states/ reports/ runs/ evidence/Committed: config.yaml, brief.md, map.md, flows/ (incl. *.journey.json), findings.*.
Git-ignored (via shipped .qa/.gitignore): config.local.yaml, evidence/, states/, reports/, runs/, logs/, .cache/.
Link-only mode stores .qa/ under ~/.qa-mcp/projects/<slug>/; an opt-in workspace: groups a
cross-domain audit under ~/.qa-mcp/workspaces/<name>/ instead.
Drivers
Both drivers implement the same neutral Driver core (capture/tap/input/press/scroll/
runFlow/observe + a capabilities() report). Browser-only powers (page registry, navigate,
inspect_ui, extract_ui, audit_ui, structured telemetry) are optional methods gated by
capabilities(), so Maestro is never forced to fake browser concepts and web-only tools fail with a
clear capability message under mobile.
maestro(mobile) — ADB screenshot + uiautomator hierarchy; taps resolve label→coordinate.playwright(web) — persistent Chromium; taps resolve label→Locator via a per-capturedata-nitpick-idtag (robust to layout shifts); console/network errors buffered forobserve; web flows are a neutral JSON step list; auth viastorageStatereferenced fromconfig.local.yaml.
start_session auto-selects the driver, or set driver: in .qa/config.yaml.
Auth (getting past login)
Most real apps need a login first. Configure it in the git-ignored .qa/config.local.yaml:
auth:
loginFlow: login # a saved flow in .qa/flows that logs in
credentials: { username: [email protected], password: secret }
headed: false # true = visible browser for manual OTP/2FA/SSO- Automatable login — put
{{username}}/{{password}}placeholders in the committedloginflow (no secrets in it); calllogin(). Creds are injected at runtime; the session is saved to.qa/.cache/auth-state.json. - OTP / 2FA / SSO — set
headed: true, log in by hand once, callsave_auth(). - Future
start_sessioncalls reuse the saved session and start already logged in.
Secrets (config.local.yaml) and the saved session (.qa/.cache/) are git-ignored.
Review ideology
REVIEW.md is the base review prompt (the how to think). qa_review composes it with the
per-project brief.md (the what to care about). Edit REVIEW.md to tune the philosophy for
every review; it reloads without a rebuild and is exposed as the qa://review-guide resource.
