Harness as MCP
forge mcp serve speaks MCP over stdio, exposing the harness as tools any MCP-capable agent can call directly — so the agent can ask the harness what it knows, instead of only being fed by hooks.
forge mcp serve # stdio JSON-RPC; wire it into your host as a serverTools
| Tool | Arguments | Returns |
|---|---|---|
forge_metrics | — | harness rollup: verify pass rate, breaker, budget, secscan, timeline |
forge_profile | — | repo-adaptive profile: stack, provider, size, relevant skills |
forge_provider | — | resolved git host + related repos |
forge_trace_show | change | that change's session timeline |
forge_budget_check | change, optional max_tokens | budget status; reports a crossed ceiling |
forge_verify | optional change | tests/lint + scenario coverage; with change, the circuit-breaker verdict |
Each tool delegates to the same forge command you'd run in a terminal, so the CLI and the MCP surface cannot drift apart.
A refusal is data, not an error
When a gate refuses — an open breaker, a crossed budget ceiling — the tool returns a result with isError: true and the message as text, not a JSON-RPC transport error. That distinction matters: the agent receives the verdict as something it can read and reason about, rather than a broken call it might retry blindly.
Queryable, not enforcing
This is the boundary
MCP makes the harness legible. It does not make it binding. An agent that can call a tool can also ignore what the tool says.
Enforcement stays where it has teeth: the non-zero exits used by live-agent hooks, pre-commit, and CI — paths the agent does not control. Use MCP so the agent can steer itself with real evidence; keep the enforced gates for the cases where being ignored is not an acceptable outcome.
Implementation note
The server is hand-rolled on stdlib JSON-RPC — no MCP SDK dependency — so forge remains a single static binary with no runtime requirements. It implements the minimal useful subset: initialize, tools/list, tools/call. Notifications produce no response, and one malformed line yields a parse error without killing the session.