Skip to main content

MCP Server

Prowl can run as an MCP server, exposing QA as a small set of named tools that any MCP-capable agent can call over stdio. The agent triggers runs and reads structured results through these tools — it never needs shell access to your repo.

This is the deepest form of the agent integration: instead of shelling out to prowl run, an agent connects once and drives QA through list_hunts, run_hunt, run_suite, and list_projects.

Prerequisites​

  • prowl must be on your PATH. Install it globally with npm install -g prowl-tools, or launch it through npx (see the npx config below). If the binary can't be found, the MCP client fails to start the server with no hunt-specific error.
  • The target project must be initialized — a .prowl/ directory with a valid config and hunts. Run prowl init and author hunts first. Pointed at an uninitialized repo, MCP tool calls fail with a missing .prowl/config.yml error.

Starting the server​

prowl mcp

This starts a stdio server for the current project — it discovers .prowl/ from the working directory, exactly like the other commands. To drive several repos from one server, pass a project registry:

prowl mcp --projects ~/.prowl/projects.yml

Configuring an MCP client​

Point your MCP client at a command that starts the server from the initialized project. Most stdio MCP clients support command, args, and env; a cwd field is not portable, so these examples use a shell wrapper to enter the project directory before launching prowl mcp. If your client has a documented working-directory setting, you can use that instead.

{
"mcpServers": {
"prowl": {
"command": "/bin/sh",
"args": ["-lc", "cd \"/path/to/your/project\" && exec prowl mcp"]
}
}
}

Tools​

ToolArgumentsReturns
list_huntsproject?Hunt names in run order
run_hunthunt, project?The full RunResult for a single hunt
run_suiteincludeTags?, excludeTags?, parallel?, logBugs?, project?Pass/fail/skip counts, the ci-result.json path, and the bug tickets created
list_projects—Registered projects (empty unless a registry is configured)

Existing guardrails (allowedDomains, forbiddenSelectors, maxSteps, maxTotalTimeMs) apply to every run the server triggers.

Controlling what the agent can do​

Prowl exposes only these four tools and never runs arbitrary shell. To restrict the agent further, allow-list tool names in your MCP client (e.g. OpenClaw) config — for example, allow list_hunts and run_suite but withhold run_hunt. That allow-listing is configured on the agent/client side, not in Prowl.

Logging bugs automatically​

run_suite runs every hunt and, by default, logs each failure as a deduplicated bug ticket in the project's docs/backlog.md, under a ## QA Findings (automated) section that stays separate from your hand-written items. A bug is identified by hunt + failing step + normalized error, so:

  • a brand-new failure creates a QA-NNN ticket with the hunt, failing step, error, and a link to the run artifacts;
  • a failure that already has an open ticket is left alone (no duplicates);
  • a failure matching something already in docs/resolved.md is logged as a regression that references the old ticket id.

Pass logBugs: false to run without touching the backlog. A run_suite response looks like this:

{
"status": "fail",
"totalHunts": 8,
"passed": 6,
"failed": 2,
"skipped": 0,
"resultPath": "/path/to/project/.prowl/runs/ci-2026-05-26_09-12-03-456/ci-result.json",
"bugs": {
"created": ["QA-014"],
"regressions": ["QA-015"],
"alreadyOpen": ["QA-009"],
"backlogPath": "/path/to/project/docs/backlog.md"
}
}

status is one of pass, fail, no-hunts, or all-skipped. When logBugs is false, the bugs arrays are empty and backlogPath is null.

tip

The same bug-logging flow is available to non-MCP consumers via the updateBacklogFromSuite() library function.

Driving multiple projects​

By default the server acts on the current directory. To drive several repos from a single server, give it a project registry — one YAML file that maps project names to repo roots. This file lives outside any repo (it spans many), not inside a target project:

# ~/.prowl/projects.yml
projects:
coupe:
root: /Users/you/projects/coupe
storefront:
root: /Users/you/projects/storefront
configPath: /custom/.prowl/config.yml # optional; defaults to <root>/.prowl/config.yml

The registry is resolved in priority order:

  1. prowl mcp --projects <path>
  2. the PROWL_PROJECTS environment variable
  3. ~/.prowl/projects.yml

With a registry loaded, every tool accepts an optional project argument that selects which repo to act on, and list_projects enumerates what's available. For example, these run_suite arguments run the smoke suite for coupe and log any failures to coupe/docs/backlog.md:

{ "project": "coupe", "includeTags": ["smoke"] }

Omit project and the tool falls back to the current directory. Naming a project that isn't registered — or naming one when no registry is configured — returns a clear error.

What's Next​