Brutalist MCP
An MCP server that runs reviews through locally installed Claude Code, Codex, and Antigravity (agy) CLIs. A roast runs the selected critics in parallel and returns their responses together. A debate assigns opposing positions to two critics across multiple rounds.
The CLI processes run on your machine; inference uses the services and credentials configured for each CLI. Findings are model output: check the cited files, commands, and sources before acting on them.
Install
Use Node.js 24 and at least one authenticated CLI. CI also tests Node.js 20.
1. Install and sign in to a critic
On macOS or Linux, install whichever CLIs you want to use:
# Claude Code
curl -fsSL https://claude.ai/install.sh | bash
# Codex
npm install -g @openai/codex
# Antigravity CLI
curl -fsSL https://antigravity.google/cli/install.sh | bash
Launch claude, codex, or agy and complete sign-in. Brutalist's Agy adapter also requires python3 on PATH and a POSIX environment; native Windows is unsupported, so use WSL there. For other platforms and installation options, use the official Claude Code, Codex, and Antigravity CLI instructions.
Brutalist prefers ~/.local/bin/agy when it exists, avoiding the Antigravity desktop launcher's PATH collision. Set AGY_BIN to the executable's path if your CLI is elsewhere.
2. Connect your MCP client
Claude Code — user scope makes the server available across projects:
claude mcp add --scope user brutalist -- npx -y @brutalist/mcp@latest
Codex:
codex mcp add brutalist -- npx -y @brutalist/mcp@latest
Codex's default MCP tool timeout is 60 seconds. Persist a larger timeout in ~/.codex/config.toml; codex mcp add has no dedicated timeout flag:
[mcp_servers.brutalist]
command = "npx"
args = ["-y", "@brutalist/mcp@latest"]
tool_timeout_sec = 9000
Brutalist waits for the critics to finish. A 9,000-second client timeout covers the default two-hour critic budget plus 30 minutes for startup and response processing. It is a suggested budget, not a minimum for every review. Increase it for debates, which run multiple turns and may retry. See Codex MCP configuration.
Other MCP clients — register a local stdio server with command npx and arguments -y, @brutalist/mcp@latest. For clients that use an mcpServers object:
{
"mcpServers": {
"brutalist": {
"command": "npx",
"args": ["-y", "@brutalist/mcp@latest"]
}
}
}
Place this in your client's MCP configuration, not a shell. The same server can be used from Cursor, VS Code, or Devin Desktop (formerly Windsurf); configuration locations and formats belong to those clients.
@latest selects the current npm release when the server is launched; an already running process keeps its loaded version. Restart or reconnect the MCP server after an update. To fix the package version, replace @latest with a version such as @1.18.10.
3. Check detection
Ask your assistant to call cli_agent_roster with {}. It reports detected CLIs and model configuration. Detection does not prove that authentication, quota, or a particular model will work; confirm with a roast.
Tools
These are MCP tools invoked by your assistant, not terminal commands. The server exposes four:
| Tool | Purpose |
|---|---|
roast | Review a path and context using a selected domain. |
roast_cli_debate | Have two critics defend explicit opposing positions. |
cli_agent_roster | Report detected critics and model configuration. |
brutalist_discover | Suggest domains from an intent string. |
Legacy names such as roast_codebase and roast_security are not registered tools. Use roast with domain instead.
Roast a repository
Call roast with:
{
"domain": "codebase",
"target": "/absolute/path/to/repo",
"context": "Review the authentication changes. Trace session creation, expiry, and authorization checks. Cite file paths and lines.",
"limit": 20000
}
Use an existing directory as target. The path is included in the critic's prompt; it does not change the subprocess working directory, which defaults to the server's launch directory. Use absolute paths and identify the files or commands you want checked in context. For domains that review an idea, plan, or other text, put that material in context:
{
"domain": "architecture",
"target": "/absolute/path/to/repo",
"context": "We plan to move invoice generation to a queue. Assess duplicate delivery, transaction boundaries, and recovery after a worker crash."
}
| Domain | Review subject | Additional arguments |
|---|---|---|
codebase | Implementation | — |
file_structure | Directory and module organization | depth |
dependencies | Package dependencies | includeDevDeps |
git_history | Commits and change history | commitRange |
test_coverage | Tests and coverage gaps | runCoverage |
idea | A proposal | resources, timeline |
architecture | System design | scale, constraints, deployment |
research | Research methods and claims | field, claims, data |
security | Security controls and threats | assets, threatModel, compliance |
product | Product decisions | users, competition, metrics |
infrastructure | Deployment and operations | scale, sla, budget |
design | Interface or visual design | medium, audience, brand, url |
legal | Legal arguments or documents | practice, jurisdiction, posture |
For design, supplying a live url gives critics a concrete interface to inspect. The domain automatically requests the registered Playwright MCP server. Playwright is the built-in integration; the first Claude browser review may download Chromium. Register additional servers through the BRUTALIST_MCP_SERVERS JSON environment variable, keyed by name with command and args. Request names with mcp_servers. Claude and Codex wire these integrations; Agy currently ignores the field. Requested integrations replace Codex's configured MCP server set for that run. Check the result for actual browser observations.
Choose critics and models
Omit clis to run all detected native critics. To select a subset, add:
{
"domain": "codebase",
"target": "/absolute/path/to/repo",
"clis": ["claude", "codex"]
}
No model override means the CLI chooses its configured/default model. Brutalist does not select the newest model or update the critic CLIs for you.
| Critic | Per-call selection |
|---|---|
| Claude Code | models.claude is passed to the CLI. |
| Codex | Uses its CLI configuration. models.codex is ignored unless the server has BRUTALIST_CODEX_ALLOW_MODEL_OVERRIDE=true; enabled overrides use discovered model migrations. |
| Antigravity | models.agy is passed through native --model. Run agy models to get choices available to your account. |
For Agy, copy a current ID or label from agy models into models.agy. Unpinned Agy responses leave the model unspecified: the adapter's plain-text output does not identify the selected model. Check Agy's local logs when you need that evidence. Brutalist disables Agy's CLI auto-update during critic runs; this does not pin the model.
Debate a decision
Call roast_cli_debate with a topic and both positions:
{
"topic": "Should invoice generation move to a queue?",
"proPosition": "Use a queue to isolate retries and absorb load spikes.",
"conPosition": "Keep generation synchronous until idempotency and reconciliation are proven.",
"agents": ["claude", "codex"],
"rounds": 2,
"context": "Current design: checkout writes the order and invoice in one database transaction. The proposed worker would receive an order ID after commit and retry on failure."
}
Debates require at least two detected CLIs. agents is optional; when supplied it contains exactly two critics, otherwise two are selected randomly. rounds accepts 1–3 and defaults to 3. The current debate handler accepts target but does not forward it to the critics; supply the evidence to debate in context. Use roast for a repository review. Positions are assigned for the debate. Its arguments are not independent endorsements. Custom routed clients are supported by roast, not debates.
Read large results and follow up
limit accepts 1,000–100,000 and sets a chunk-size target in characters, not tokens. Roast pagination defaults to 90,000 characters; debate and automatic pagination use smaller defaults. Chunk boundaries, a minimum chunk size, and response headers mean it is not a hard output ceiling. Set it explicitly if your MCP client truncates results.
For another page, reuse the returned context_id and the next offset reported in the response. Keep the original domain and target; omit resume. For example, if the response asks you to continue at offset 20,000:
{
"domain": "codebase",
"target": "/absolute/path/to/repo",
"context_id": "<returned context_id>",
"offset": 20000,
"limit": 20000
}
You can also pass a cursor such as "offset:20000" instead of offset. Page reads retrieve cached output. The cache defaults to two hours and belongs to the server process; a restart loses it.
For a fresh follow-up, include the relevant earlier findings in context and set force_refresh: true:
{
"domain": "codebase",
"target": "/absolute/path/to/repo",
"force_refresh": true,
"context": "The earlier review found duplicate invoice creation after retries. Check whether the new idempotency key prevents it; inspect both the database constraint and worker retry path."
}
The tool also accepts context_id with resume: true for history-based continuation, but the current handler has limitations: filesystem follow-ups record the target path as the new conversation message, and a cache hit can return earlier output without running critics. force_refresh skips history loading. Use the fresh-follow-up pattern above when you need a new review.
Use force_refresh: true after changing files, routed clients, or MCP integrations. File contents, clients, and mcp_servers are not all represented in the cache key.
Custom Claude-compatible endpoints
roast can add named Claude Code clients routed through Anthropic-compatible endpoints. Set the token in the MCP server's environment and reference its variable name:
{
"domain": "codebase",
"target": "/absolute/path/to/repo",
"clis": [],
"clients": [
{
"id": "gateway",
"provider": "claude",
"baseUrl": "https://gateway.example.com",
"authTokenEnv": "REVIEW_GATEWAY_TOKEN",
"model": "<model supported by your endpoint>"
}
]
}
clients is additive to native critics; clis: [] runs only named clients. Up to 16 clients are accepted. Endpoint, model, and credential-routing fields are supported only for the claude provider. You can also configure default clients through the server's BRUTALIST_CLAUDE_CLIENTS JSON environment variable. A nonempty per-call clients array replaces those defaults.
Routed clients use separate configuration directories under ~/.brutalist/claude-clients/<id> unless configDir is supplied. They do not inherit native Claude credentials unless includeProcessAuth: true is set. Their smallFastModel defaults to the routed model.
The default containment setting, named hardened, suppresses requested MCP integrations. It does not sandbox shell commands or network access: Bash, WebFetch, and WebSearch remain available. containment: "standard" restores requested MCP integrations.
Execution and troubleshooting
Critics can inspect files and invoke tools. Codex runs with --sandbox read-only. Claude denies its named mutation tools but enables Bash and web tools while bypassing permission prompts; this is not a filesystem sandbox. Agy runs with --sandbox and permission prompts disabled, and can write scratch artifacts. External MCP tools add their own capabilities. Use a checkout and credentials appropriate for those processes.
A roast can return findings when only some critics succeed. Check which critics contributed; a missing critic is not agreement. Error text may be generic or redacted. Authentication failures, quota limits, unsupported models, and client timeouts need separate diagnosis.
Useful server environment variables:
| Variable | Purpose |
|---|---|
BRUTALIST_TIMEOUT | Per-agent roast timeout in milliseconds; default 7200000 (two hours). |
BRUTALIST_AGY_TIMEOUT | Agy timeout ceiling in milliseconds; can shorten, not extend, the selected agent budget. |
AGY_BIN | Override the Agy executable path. |
BRUTALIST_CODEX_ALLOW_MODEL_OVERRIDE | Set exactly true to pass models.codex to Codex. |
BRUTALIST_MCP_SERVERS | Additional MCP server definitions as a JSON object keyed by server name. |
BRUTALIST_CACHE_TTL_HOURS | Result-cache lifetime; default 2. |
BRUTALIST_LOG_FILE | Set exactly true to enable NDJSON file logs. |
BRUTALIST_LOG_DIR | Override the log directory; default ~/.brutalist-mcp/logs. |
BRUTALIST_LOG_LEVEL | Minimum file-log level; default info. |
Set these on the MCP server process, using your client's server environment configuration. The client tool timeout is a separate setting. Logs can contain paths, model names, and prompt excerpts; redaction does not make the entire file safe to share.
The legal, research, and security prompts ask critics to verify external authorities and label citations with [VERIFIED: URL | "quote"], [SUPPLIED: location | "quote"], or [UNVERIFIED: reason]. These are prompt instructions, not a programmatic guarantee that a citation was checked.
GitHub pull-request reviews
The repository also contains a GitHub Action and orchestrator. The Action posts findings as a PR review and has its own CLI installation and credential requirements. Use its README and input definitions for workflow setup, OAuth provisioning, and custom-claude-clients configuration.
Development
npm ci
npm run build
npm test -- tests/unit tests/integration/pagination-e2e.test.ts tests/integration/cache.integration.test.ts tests/smoke
The CI workflow also tests and builds the orchestrator and GitHub Action. Tagged releases publish the MCP package to npm with provenance after those checks pass.
License: MIT · Report an issue