Integrate your agent
Two ways to route a real agent through Axtary: the Claude Code hook (gates Claude Code's file tools) and the MCP wrapper (gates any MCP client — Claude Code, Cursor, Codex). Both use the same policy file and the same hash-chained ledger.
Option 1 — Claude Code PreToolUse hook
Gates Claude Code's Read/Glob/Grep/Write/Edit tools by normalizing each into an Axtary content action and asking the local proxy for a decision.
1. Start the proxy in your project (leave it running):
axtary proxy --config axtary.yml
2. Register the hook in the project's .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Glob|Grep|Write|Edit|NotebookEdit",
"hooks": [
{
"type": "command",
"command": "node /ABS/PATH/axtary/packages/cli/dist/bin.js hook claude-code --proxy http://127.0.0.1:7331 --owner user:you@example.com --repo your-org/your-repo",
"timeout": 10
}
]
}
]
}
}
3. In a Claude Code session in that project, ask it to read .env.production — it's denied with the blocked prefixes named, and Claude self-corrects. Every decision is a ledger record (.axtary/actions.jsonl).
What each decision does — and where it's enforced
| Axtary decision | Claude Code CLI | Claude Code VS Code extension | Notes |
|---|---|---|---|
allow | tool runs | tool runs | |
deny | blocked ✓ | blocked ✓ | works everywhere — secrets/denied paths can't be read or written |
step_up → ask | prompts for approval ✓ | ⚠️ not prompted yet | the tool currently proceeds in the VS Code extension |
Step-up caveat (important, honest): Axtary returns
step_upcorrectly and records it in the ledger, and the Claude Code CLI honors it (prompts you). But the Claude Code VS Code extension currently ignores a PreToolUseaskdecision and falls back to its own permission rules (anthropics/claude-code#13339) — so the edit can proceed without an approval prompt.denyis unaffected. For guaranteed, payload-bound step-up, use the dashboard approval queue / proxy-executed path (axtary run workflow … --hosted-approval), which binds approval to the exact payload hash rather than relying on the editor's prompt.
Known scope
Bashis not gated by the hook — an agent couldcat .envthrough it. Claude Code's own Bash permissioning applies; shell normalization is a follow-up.- The hook governs file tools as repo content actions. MCP tool calls are gated by the wrapper below, not the hook.
Option 2 — MCP wrapper (any MCP client)
axtary mcp serve is a stdio MCP server. Every tools/call is normalized, checked against policy with the tool's definition hash pinned (drift = deny), pass-signed, executed through the wrapped upstream, and ledgered.
Run it (demo mode exposes a deterministic read_fixture tool — no upstream needed):
axtary mcp serve --config axtary.yml
# or wrap a real upstream:
axtary mcp serve --config axtary.yml --wrap 'npx -y @modelcontextprotocol/server-everything'
Connect it — pick the path that matches your client
Claude Code CLI (most reliable):
claude mcp add axtary -- node /ABS/PATH/axtary/packages/cli/dist/bin.js mcp serve --config /ABS/PATH/axtary.yml
claude mcp list # confirm "axtary" is registered
Claude Code VS Code extension / Cursor — project-scoped config. Create .mcp.json (Cursor: .cursor/mcp.json) in the project root:
{
"mcpServers": {
"axtary": {
"command": "node",
"args": ["/ABS/PATH/axtary/packages/cli/dist/bin.js", "mcp", "serve", "--config", "/ABS/PATH/axtary.yml"]
}
}
}
MCP onboarding gotcha: a project
.mcp.jsonis only loaded when the editor's workspace is that project folder, and you must approve the server when prompted (or via the client's MCP panel //mcp). Opening a different folder, or adding.mcp.jsonto an already-open session, means the server won't appear. If your client has noclaude/CLI on PATH, use the project-config route and open the folder directly.
Then ask the agent: "Call the axtary read_fixture tool with fixtureKey repo_primer." Confirm it landed:
tail -3 .axtary/actions.jsonl # "tool":"mcp.tool.call", decision "allow"
The tool-poisoning block (deterministic, no client needed)
axtary mcp drift-demo # exit 0 iff the drift was blocked
The tool runs at its reviewed hash, then the definition mutates (a hidden exfiltration instruction) and the identical call is denied with mcp_definition_hash_not_allowed before the upstream runs — a name-based allowlist would have executed the mutated tool.
MCP step-up note
step_up decisions for MCP tools currently deny at the wrapper (there's no interactive approval channel inside MCP). Route step-up workflows through the dashboard approval queue instead.
Which to use
- Claude Code, file edits in an editor: the hook (with the step-up caveat above).
- Any MCP client, or you want definition-hash provenance: the MCP wrapper.
- Guaranteed payload-bound human approval: the dashboard approval queue (works regardless of editor).