MCP Server · node9 documentation
Node9 MCP Server
Native MCP tools that let Claude, Cursor, and Gemini interact with node9 directly.
The Node9 MCP Server is a stdio process that speaks standard JSON-RPC 2.0. Unlike the MCP Gateway (which wraps other servers), this server is node9's own surface — it exposes node9 capabilities as tools the AI can call directly: policy and shield management, audit and report queries, status, and rule authoring.
Architecture
Claude / Cursor / Gemini (MCP client)
↓ stdio (JSON-RPC 2.0)
Node9 MCP Server ← node9 mcp-server
↓ direct function calls
~/.node9/audit.log ← intercept history
~/.node9/config.json ← merged policyNo daemon required. The server reads state directly from disk.Setup
Auto-registered by node9 init
Running
node9 init adds the MCP server entry to your agent config automatically — no extra step needed.What gets added to your config
// ~/.claude.json (Claude Code)
// ~/.gemini/settings.json (Gemini CLI)
// ~/.cursor/mcp.json (Cursor)
{
"mcpServers": {
"node9": {
"command": "node9",
"args": ["mcp-server"]
}
}
}Available Tools
Status & Inspection
node9_statusread-only
Returns daemon state, hook wiring, active mode, audit-event counts, and connected workspace. The same data
node9 status prints to the terminal.node9_config_getread-only
Returns the merged effective configuration (defaults + global + project + shields). Shows which file each field came from.
node9_policy_getread-only
Returns the active policy: smart rules, sandbox paths, ignored tools, dangerous words. Useful for the agent to self-introspect what is allowed before attempting an action.
node9_sessionread-only
Returns information about the current trust session — active grants, expiry times, and which tools are currently auto-approved.
Audit & Reporting
node9_audit_getread-only
Reads
~/.node9/audit.log. Supports filters: tool name, decision, time range. Returns structured entries with redacted secrets.node9_reportread-only
Aggregated summary across a time window: allowed / blocked / DLP findings / cost. Same output as
node9 report.node9_scanread-only
Forecasts what would have been blocked across recent agent history — useful for the agent to ask "would this have been allowed?" before acting.
Shields, Rules & Approvers
node9_shield_listread-only
Lists every available shield with enabled/disabled status and a short description of what it blocks.
node9_shield_enablemutation
Activates a shield by name (e.g.
postgres, aws). Writes to ~/.node9/shields.json.node9_shield_disablemutation
Deactivates a shield by name. The agent should ask the user before disabling, since this widens the attack surface.
node9_rule_addmutation
Appends a smart rule to the active policy. Takes a full SmartRule object — tool, conditions, verdict, reason. Useful for "remember not to do this" workflows.
node9_approver_listread-only
Lists which approval channels are currently enabled (native, browser, cloud, terminal).
node9_approver_setmutation
Enables or disables an approval channel. Mirrors
settings.approvers.* in the config file.Example conversation
Claude using the MCP server
You: why did node9 block that command?
Claude: Let me check what node9 decided.
[calls node9_explain { command: "cat ~/.ssh/id_rsa" }]
BLOCK — shield:project-jail:block-read-ssh
reads a path in the credential jail (~/.ssh/*)
That path is jailed, so I can't read it. If you need the public
key instead, ~/.ssh/id_rsa.pub is not jailed — want me to use that?Manual testing
Test over stdio directly
# Start the server
node9 mcp-server
# Paste these lines one at a time:
{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"test"},"capabilities":{}}}
{"jsonrpc":"2.0","method":"tools/list","id":2}
{"jsonrpc":"2.0","method":"tools/call","id":3,"params":{"name":"node9_status","arguments":{}}}Why expose these as MCP tools?
Giving the agent direct access to status, policy and audit lets it self-correct: it can check whether an action would be blocked before attempting it, inspect what just got rejected, and revert its own changes without needing the user to drop into the CLI.