The AIShell-Gate MCP server exposes the policy engine and execution gateway to Claude Code, Cursor, and any MCP-compatible AI environment. Eleven tools. Two editions. One configuration file. Start with the Quick Start block at the top — four steps and you're running. The rest of this document is reference.
This is a beta release. Do not use on production systems. AIShell-Gate raises the cost and visibility of unsafe AI-generated commands; it does not guarantee total protection. Report issues to info@aishellgate.com.
aishell-gate-mcp.json — defaults work as-is"confirm_mode": "relay" to enable human confirmation relay through Claude — see §05.--allowedTools flag suppresses Claude Code's per-tool approval prompts for aishell-gate tools. The gate's own policy and confirmation layer remains fully active — this removes only the redundant outer prompt. For a persistent setting and stronger options, see §04.get_version response shows the edition, version strings, and available tools. A successful evaluate_plan response shows a per-command policy assessment — no execution happens until you call execute_plan.The AIShell-Gate MCP server is a Python stdio process that translates MCP tool calls from an AI coding environment into subprocess invocations of the two AIShell-Gate binaries. It has no policy logic of its own. It does not execute commands on its own. It is a structured bridge between the AI agent and the existing policy and execution architecture.
The server exposes eleven tools. Nine are available in both Standard and Enterprise editions. Two require Enterprise. The AI agent calls get_version on first connection to discover which tools are available and which edition is installed.
Multi-command plan assessment. No execution. The primary pre-flight tool.
Live execution of a plan. Pre-flight runs automatically. plan_only and relay confirmation modes both work in either edition.
Detect edition, version strings, and available tools. Call this first on every new connection.
Single-command quick assessment with full flag catalog analysis. Faster than a full plan for ad-hoc checks.
Emit the built-in policy layer as an editable JSON file. Starting point for custom policy authoring.
Submit a human confirmation response to a waiting execute_plan relay. Requires confirm_mode: "relay". Available in both editions.
Poll for the result of an async relay execution, or retrieve the next pending confirmation. Requires confirm_mode: "relay". Available in both editions.
Run a single shell command through the policy engine and executor in one step. Returns stdout, stderr, exit code, and the policy decision. Prefer this over execute_plan for single commands. Available in both editions.
Download and install the two engine binaries from the latest GitHub release (Linux x86-64). Does nothing unless called with confirm=true — call once to preview, again with confirm=true to download, checksum-verify, and install. Available in both editions.
Run a test suite of command/expected pairs. PASS/FAIL per assertion. Regression testing after policy changes. Enterprise only.
HMAC chain integrity verification for exec or policy audit logs. Enterprise only.
A shell script is a sequence of commands toward a goal. So is an AIShell-Gate plan. The difference is everything between the commands and the kernel — policy evaluation, risk scoring, confirmation gates, and a tamper-evident audit trail that a shell script cannot provide. The plan model is limited: no pipes, no branching, no conditionals. But for sequences of known actions toward a stated goal, it is not just safer than a shell script. It is auditable in ways a shell script never can be. See §09 →
If you have arrived at this section because the plan model is not clicking, you are in good company. The program's most common point of confusion is not the policy layer, the audit chain, or the two-binary split — those land quickly. The confusion is more fundamental: a decades-old reflex about how AI agents work with Unix is silently breaking, and it is not always obvious that it is the reflex that is wrong.
This section is written bluntly. It is here to name the reflex, show you why it fails, and replace it with a mental model that fits what the system actually does.
Every other MCP server you have used follows the same shape. The server exposes a list of capability-shaped tools: write_file, read_file, edit_file, list_directory, run_command. The AI calls them one at a time. Each call does one small thing. Composition is the AI's responsibility — it strings the calls together in whatever order makes sense.
When you open AIShell-Gate's MCP and see only evaluate_plan and execute_plan, your reflex is to look for the file-writing tool. You scan the tool list again. You check the documentation for what you must have missed. You start to suspect something is wrong with the installation.
Nothing is wrong with the installation. The reflex is the problem. There is no write_file tool because AIShell-Gate is not a filesystem MCP. It is a policy-gated execution MCP that happens to be able to affect files as a side effect of running commands. Those are different categories of thing, and conflating them is where understanding breaks down.
The reflex comes from a real tradeoff in how existing tools were designed. A capability-shaped MCP server is easy to use safely because it is narrow. write_file can only write files. It cannot escalate privilege, spawn a shell, or touch the network, because the tool surface simply does not expose those things. Safety comes from what the tool cannot do.
AIShell-Gate takes the opposite approach. It exposes the whole operating system as a submission surface and derives safety from what the policy will allow, not from what the tool surface can address. This is a more powerful model — a single MCP can govern anything the OS can do — but it requires you to think in commands and policy, not in capabilities and tools.
The payoff is that you stop building bespoke MCP servers for every capability you want to expose. One MCP, one policy file, one audit chain, and the AI can do anything you are willing to permit. The cost is that you have to think about the system the way a Unix operator thinks about it: in commands and their effects, with a deterministic policy as the gate.
Before showing what the model can do, it helps to be explicit about what it cannot do. These constraints are not limitations to work around — they are the definition of the model. Every one of them exists because allowing it would reintroduce the attack surface the gate is built to eliminate.
| A plan has no | Because |
|---|---|
Pipes (|) | Pipes require a shell. The execution path has no shell. Rejected as a metacharacter. |
Redirection (>, >>, <) | Redirection is shell behaviour, not command behaviour. Rejected as a metacharacter. |
Heredocs (<<EOF) | Heredocs are shell syntax for stdin redirection. Rejected as a metacharacter. |
Command substitution ($(...), backticks) | Substitution runs an inner command and captures its output. A second execution path outside policy review. Rejected. |
Conditionals (&&, ||) | Branching on exit codes is shell control flow. Rejected. (See "State between plans" below for the right approach.) |
| Loops | Shell control flow. Not expressible in a plan. |
Variable expansion (${VAR}) | Environment-dependent behaviour makes audit records non-deterministic. Rejected. |
| Quoted arguments with spaces | Quotes are shell syntax. Supporting them would require implementing a shell grammar subset, which is a bypass surface. |
| State between plans | Each plan is stateless and self-contained. No accumulated context, no long-lived process. This is by design. |
These nine constraints are the mental model. Internalise them and the rest of the system's behaviour follows.
Three analogies that capture the plan model better than "MCP tool":
A plan is a CI job submission, not a terminal session. When you push a commit to a CI server, you are submitting a declarative description of work to be done. The CI server evaluates it against rules (branch protections, required reviewers, merge policy), requires approvals where necessary, runs the job, and produces an immutable record. You do not ssh into the runner and vim a file. You submit a job; the job runs. AIShell-Gate is the same shape, scaled down to the individual command level.
A plan is a signed transaction, not an API call. A database transaction is atomic: a group of operations that either all succeed under the committed rules or all fail together. You cannot reach into the middle of a transaction and change it based on intermediate state. A plan is the same. All the confirmations are collected before any action runs; once execution starts, the plan proceeds deterministically or stops cleanly.
A plan is a work order, not a conversation. When you hand a work order to a contractor, it specifies the goal and the sequence of tasks. If the contractor discovers midway that the plan does not fit the site, they do not improvise — they come back and get a new work order. That is exactly the plan segmentation pattern. Work requiring intermediate judgment is split across multiple plans, with the calling environment reading results and submitting the next plan.
The fastest way to build the new model is to see the old reflex fail against specific tasks and see what the right answer looks like.
The failing reflex. You reach for a write_file tool that does not exist, then try:
# Plan action — this will be denied at evaluation
{"cmd": "echo 'FROM python:3.11' > Dockerfile"}
The policy engine rejects this at step 1 of evaluation, before any rule lookup. > is a shell metacharacter. There is no shell, so the character has no meaning the executor can honour. The action is denied with a parse-level error.
The model-fit answer. There are three idiomatic approaches. All of them work because none of them need a shell:
cp or mv command to place it in the target location. Policy evaluates cp ./staging/Dockerfile ./Dockerfile like any other file operation — subject to writable_dirs, confirmation level, and audit record.git pull or git checkout. The writing happens in git; the gate is only involved in the pull. This is the most common real-world pattern.install or cp with a pre-written source file. If the Dockerfile content is reproducible (a template with no per-run variation), keep it in a known location and install -m 0644 /path/to/Dockerfile.template ./Dockerfile. One command. No shell. Fully auditable.The failing reflex. You reach for the conditional:
# Plan action — this will be denied
{"cmd": "make test && ./deploy.sh"}
&& is a shell metacharacter. Denied at parse.
The model-fit answer. Plan segmentation. Submit plan A, read its result in your orchestration code, then submit plan B based on what came back:
# Plan A — run the test
{"goal": "run test suite", "actions": [{"cmd": "make test"}]}
# Calling code inspects plan A's exit code.
# If zero, submit plan B. If not, surface the failure and stop.
# Plan B — deploy, submitted only on success
{"goal": "deploy build artifact", "actions": [{"cmd": "./deploy.sh"}]}
This is not a workaround. It is the model working correctly. Each plan is a signed transaction. Branching logic lives in the calling environment where it belongs — the Python script, the orchestration agent, the CI pipeline definition — not inside a plan where it would be hidden from policy review.
The failing reflex. The pipe:
# Denied — pipe is a metacharacter
{"cmd": "find . -name '*.py' | xargs wc -l"}
The model-fit answer. Use a single command that does the composition internally. Many Unix utilities have flags that replace common pipeline patterns:
# find with -exec: no shell, no pipe, composition done inside find
{"cmd": "find . -name *.py -exec wc -l {} +"}
This works because find spawns wc directly via its own fork/exec machinery — no shell, no pipe. The composition is semantic, not syntactic. This pattern applies broadly: grep -r instead of find | xargs grep, sort -u instead of sort | uniq, awk instead of cut | head.
Three habits replace the ones you are unlearning:
Think in commands, not tools. When you want to affect the system, ask "what Unix command does this?" — not "what MCP tool does this?" There is no one-to-one mapping between capabilities and tools here. The mapping is between capabilities and allowed commands under the active policy.
Move composition out of the command string. Anything that would be a pipe, a conditional, or a substitution in a shell script moves up one level — into the orchestration code that submits plans. The plan itself stays flat and declarative.
Treat each plan as atomic. A plan is not a script; it is a transaction. Compose transactions, do not embed logic inside them. The calling code decides what transaction to submit next based on what the previous one returned.
The MCP server is a single Python 3 script with no external dependencies. Python 3.8 or later is required. The AIShell-Gate binaries (aishell-gate-exec and aishell-gate-policy) must be installed and accessible before the server will function.
The --version output from the MCP server lists the protocol version, all registered tools, and which edition tools require. If the binaries are not found, the server will start but all tool calls will return structured error responses rather than crashing — making misconfiguration diagnosable from within Claude Code.
The MCP server can run from any directory. For system-wide availability, install it alongside the binaries:
aishell-gate-mcp.json.
Add the server to your project's .mcp.json file. The AI coding environment discovers and launches it automatically on startup.
Restart Claude Code or Cursor after adding this entry. The tools will appear in the available tool list. Use get_version to confirm the connection and edition.
On some Claude Code versions the server in .mcp.json is not picked up on restart. The aishell-gate tools never appear in the tool list, and no error is reported — the entry is simply ignored. Restarting repeatedly does not resolve it.
The workaround is to force Claude Code to re-read its project configuration by making an actual edit to .claude/settings.json and saving it:
Create the file if it does not exist, or add a line to it if it does, then save and restart. The tools should then appear. get_version is a good first entry to add — it is the tool you will use to confirm the connection anyway, and §04 lists the full set worth allowing.
Two independent confirmation layers can apply to every MCP tool call. By default, Claude Code asks for approval before calling any MCP tool — including evaluate_plan, which never executes anything. Separately, AIShell-Gate's own policy engine assigns a confirmation level (none, plan, action, or typed) to every allowed action. These two layers stack: a single-command plan with no policy-level confirmation requirement can still produce a Claude Code approval prompt, because Claude Code does not know in advance that the gate would have allowed it without confirmation.
For operators who want a single, predictable confirmation surface — the gate's own policy engine, and nothing else — Claude Code's tool-approval layer can be turned off for AIShell-Gate specifically.
This auto-approves every aishell-gate tool call for the current Claude Code session. It does not persist — the flag must be passed each time Claude Code is launched.
Place the following at .claude/settings.json in the project root:
Restart Claude Code after adding or editing this file — permission settings are not re-read mid-session.
aishell-gate tools are not appearing in the tool list, set up this file first; it may resolve both problems at once.
mcp__{server-name}__{tool-name}. If the server is named something other than aishell-gate in .mcp.json, every line above must be updated to match, or the rules will silently fail to apply.
verify_policy and verify_audit_log are intentionally left out of this list — they are Enterprise-only and should not be auto-allowed on Standard installs; add them only when deploying the Enterprise edition. confirm_action and get_execution_result are left out for a different reason: they are available in both editions, but do nothing unless confirm_mode: "relay" is set, so there is no benefit to auto-allowing them under the default plan_only mode. Add them once relay mode is configured — see §05. If instead you're configuring operator_pipe mode, go a step further and add both to "deny" rather than just leaving them unlisted — since Claude has no legitimate use for them there, an explicit deny closes off the only tools it could otherwise attempt to (mis)use to supply a confirmation itself.
operator_pipe instead? Its settings.json looks the same as Option B above, minus confirm_action/get_execution_result from allow and with them added to an explicit "deny" list, alongside "Bash". See §05 for the full confirm_pipe configuration.
Scope is per-project: this file only affects the project it sits in. For the same behavior across every project, place an identical file at ~/.claude/settings.json instead.
.claude/settings.json is parsed as strict JSON, which has no comment syntax — //, #, and /* */ will all cause a parse failure. To annotate the file, either keep notes in a separate document, or add an unofficial "_comment" key, which the parser currently ignores. Validate the file after any manual edit: python3 -m json.tool .claude/settings.json > /dev/null && echo OK.
The settings above remove Claude Code's approval prompt for AIShell-Gate's own tools, but they do not change what Claude Code can do. Claude Code's native Bash tool remains available alongside the gate's tools, and Claude may use either one — for a trivial command like ls, it will often reach for the native tool simply because it is the lower-friction option. For a security or policy gate, an optional gate is a significantly weaker guarantee than a mandatory one.
Two levels of enforcement are available, depending on how strict the deployment needs to be:
Soft (instruction-level, not enforced). Add a line to the project's CLAUDE.md:
This nudges Claude's tool choice but does not remove the option. Claude can still fall back to native Bash, particularly for commands that look trivial.
Hard (actually enforced). Add a deny rule for the native Bash tool in .claude/settings.json, alongside the allow list above:
This removes the native shell tool from Claude's toolset entirely. Claude must route any shell-like action through AIShell-Gate's tools, or not perform it at all.
The server reads aishell-gate-mcp.json from the working directory, or from the path given via --config. All fields are optional. A missing file is not an error — defaults are used throughout.
| Field | Default | Description |
|---|---|---|
| exec_binary | "aishell-gate-exec" | Path to the executor binary. Resolved via PATH if not absolute. Must contain a '/' to prevent PATH substitution attacks if set explicitly. |
| policy_binary | "aishell-gate-policy" | Path to the policy engine binary. Resolved via PATH if not absolute. |
| preset | "ops_safe" | Built-in policy preset. Standard edition: read_only, ops_safe, dev_sandbox. Enterprise edition adds: ci_build, ci_deploy, ci_admin, danger_zone. Applied to all tool calls that involve policy evaluation. |
| jail_root | null | Restrict write-like commands to this path tree. Forwarded to the policy engine as --jail-root. Required when using CI presets for path containment. |
| sandbox | null | Sandbox mode hint forwarded to the policy engine. Values: none, cwd_jail, chroot, container, userns. Advisory only except cwd_jail, which is actively enforced. |
| policy_base enterprise | null | Path to the base policy override file. Applied below preset in evaluation order. |
| policy_project enterprise | null | Path to the project policy override file. Applied above base, below user. |
| policy_user | null | Path to the per-user policy override file. Highest priority layer. A deny at any layer is final. Available in both editions. |
| source | "ai" | Source identity label applied to all plans. Set by the deployer — the AI plan cannot override this. Tells the policy engine who is submitting commands. Values: ai, human, broker, scheduled (the legacy aliases raw, envelope, and web are also accepted). |
| audit_log | null | Path for the executor audit log (chain_hmac format). Written by aishell-gate-exec. Do not point this at the same file as policy_audit_log — the formats are incompatible. |
| policy_audit_log | null | Path for the policy engine audit log (entry_hash format). Written by aishell-gate-policy. Separate file from audit_log. |
| audit_key enterprise | null | Path to HMAC key file for verify_audit_log. Exec key format: 64 ASCII hex characters (32 bytes). Policy key format: 64 raw binary bytes. These two formats are not interchangeable — use the correct key for the correct log type. |
| eval_timeout | 30 | Seconds before the policy engine subprocess is killed. 0 disables. The binary default is also 30; this field only sends the flag if the value differs from the default. |
| input_timeout | 30 | Seconds to wait for stdin plan data before failing. 0 disables. Has no effect when reading from a file. |
| max_response_bytes | 0 | Kill the policy engine and fail closed if its response exceeds this many bytes. 0 uses the binary default of 8 MiB. |
| extra_flags | [] | List of additional flags forwarded verbatim to aishell-gate-exec. Use for flags not covered by the standard config fields. |
| confirm_mode | "plan_only" | Controls how commands requiring human confirmation are handled. plan_only — block execution and return a structured error listing which actions require confirmation; the operator must lower the confirm level in policy or run those commands manually. relay — launch execution asynchronously and relay confirmation requests to the human via Claude using the confirm_action and get_execution_result tools; convenient, but Claude itself carries both the request and the response, so nothing here proves an answer came from the operator rather than the agent. operator_pipe — point aishell-gate-exec directly at a real, operator-owned --confirm-pipe session (see confirm_pipe below); execute_plan simply blocks until the operator answers, this server never sees the request or a typed challenge code, and confirm_action/get_execution_result are not used. All three modes are available in both editions. operator_pipe is the one that brings MCP confirmation to genuine parity with the SSH operator relay. |
| confirm_pipe | null | Only read when confirm_mode is operator_pipe. Basepath of the FIFO pair (BASEPATH.req / BASEPATH.resp) an aishell-gate-confirm session run by the operator already owns — e.g. "/run/aishell-gate/confirm". Forwarded as exec's own --confirm-pipe. Required when confirm_mode is operator_pipe; omitting it returns a configuration error rather than falling back to another mode. |
| confirm_lock | null | Optional, only meaningful with confirm_pipe set. Forwarded as exec's --confirm-lock. Needed if more than one AI session may share the same operator pipe at once — see aishell-gate-exec(1). |
| confirm_timeout | null | Optional, only meaningful with confirm_pipe set. Seconds forwarded as exec's own --confirm-timeout, bounding how long execute_plan waits on the operator. Unset uses exec's own default (120s). |
ci_build and ci_deploy presets are designed for unattended pipelines and require both Enterprise edition and --mode batch to function correctly. This flag must reach aishell-gate-policy, which means it goes after the -- separator in extra_flags. Add the following to aishell-gate-mcp.json when using either CI preset:
"extra_flags": ["--", "--mode", "batch"]
-- is required. Everything after it is forwarded verbatim to the policy engine. Flags before -- are consumed by the executor. See the executor man page for the full forwarding convention.
chain_hmac and entry_hash respectively. Never point audit_log and policy_audit_log at the same file. Mixing them will produce an unverifiable log and will cause verify_audit_log to report errors.
These five core standard tools are documented in detail below. Two more Standard tools — run and install_engine — are summarised in §01. All edition detection is automatic — the server calls --version on both binaries at startup and caches the result.
Report the installed edition, version strings for both binaries, a map of which tools are available, and a summary of active configuration. Call this first on every new connection. The response tells the AI agent exactly what it can and cannot do before it attempts any other tool call.
No arguments required.
edition — "standard", "enterprise", or "unknown"exec_version and policy_version — first line of each binary's --version outputavailable_tools — map of tool name to boolean availabilityenterprise_features — map of Enterprise-only feature availabilityconfig_summary — active preset, jail root, audit log paths, key statusAt the start of every session. If the result shows "edition": "unknown", the binaries may not be installed or reachable — check exec_binary and policy_binary in aishell-gate-mcp.json.
Submit a goal and a list of commands to the policy engine for assessment without executing anything. The internal mechanism is --dry-run-json, which runs the full policy evaluation for every action and returns a machine-readable JSON document. Call this before execute_plan to identify denied actions and required confirmation levels before any command reaches the system.
goal (required) — human-readable description of what the plan is trying to achievecommands (required) — list of shell command strings, maximum 24strategy (optional) — "fail_fast" (default) or "best_effort"overall_decision — "allow" or "deny"actions — per-action array: decision, confirm level, risk score, blast radius, resolved binary path, argv, reason, flag assessmentsummary — total, allowed, denied, max confirm level, blocking countguidance — human-readable string summarising what needs attentionBefore every execute_plan call. Also useful when helping a user understand why a command would be denied, or when building a plan that needs to stay within a particular confirmation level.
Submit a goal and list of commands for live execution via aishell-gate-exec. A pre-flight policy evaluation runs automatically before any command reaches the system. Plans with denied actions are rejected immediately. How commands requiring confirmation are handled depends on confirm_mode in aishell-gate-mcp.json.
goal (required) — human-readable description of intentcommands (required) — list of shell command strings, maximum 24strategy (optional) — "fail_fast" (default) or "best_effort"executed — boolean; true when the commands actually ran, whatever they returned. This is not "succeeded"succeeded — boolean; true only when everything ran and exited 0policy_allowed — boolean; false only when policy denied the plancommand_exit_code — present on exit 7: the command's own exit statusexit_code — the executor's exit code (0 = all succeeded)outcome — human-readable outcome stringblocked_reason — present when not executed: "policy_denied" or "confirmation_required"denied_actions or actions_requiring_confirmation — detail on what blocked executionstatus — in relay mode: "pending_confirmation" when waiting for human inputexecution_id — in relay mode: token for confirm_action and get_execution_resultconfirm_path — in operator_pipe mode: always "operator_pipe"; there is no execution_id or pending_confirmation status, since the call already blocked until the operator answeredtimed_out: truerm nofile, a failing test suite, grep with no match. When you see 7, read stderr_tail and fix the command. Do not rewrite it to satisfy policy; policy did not object. The response carries command_exit_code with the command's real status, plus succeeded and policy_allowed so the two questions can be asked separately.plan_only mode (default, both editions), commands at confirm level action or typed block execution — the response lists the specific commands so the operator can lower the confirm level in policy or run them manually. In relay mode (also both editions), execution is launched asynchronously and confirmation requests are relayed to the human via Claude using confirm_action and get_execution_result — see §07; Claude carries both the request and the answer, so this is a convenience, not a guarantee that the answer came from the operator. In operator_pipe mode, this call blocks while aishell-gate-exec talks directly to a real, operator-owned --confirm-pipe session — Claude never sees the request or a typed challenge code, which is what actually brings MCP confirmation to parity with the SSH operator relay.
Evaluate a single raw command string directly through the policy engine with --json. Returns the full JSON assessment including per-flag catalog analysis, risk score, blast radius, IO classification, confirmation level, taint status, and deny suggestions. Faster and simpler than evaluate_plan for ad-hoc single-command checks — no goal or envelope required.
command (required) — the shell command string to evaluate, e.g. "rm -rf /tmp/old"assessment — full JSON output from the policy engine, including:
safe, warn, danger, or unassessedWhen a user asks why a specific command was denied, what confirmation level a command requires, or what flags the policy considers dangerous. Also useful when building or debugging policy rules — evaluate a command against a modified policy file to see the effect immediately.
Emit the built-in policy layer as a ready-to-edit JSON override file via --dump-standard-template. The output includes all rule arrays — cmd_allow, cmd_deny, arg_rules, path_rules, net_rules — along with a schema header documenting every available key and the _replace flags. Use the result as a starting point for custom policy files rather than writing rules from scratch.
preset (optional) — which preset to template. Defaults to the active configured preset. Standard: read_only, ops_safe, dev_sandbox. Enterprise only: ci_build, ci_deploy, ci_admin, danger_zonetemplate — the parsed JSON policy object, ready to useheader — the plain-text schema documentation that precedes the JSON in raw outputusage — instructions on which config fields to set to activate the fileCall get_policy_template, save the template JSON to a file (e.g. my-project-policy.json), edit the relevant rules, then set policy_project in aishell-gate-mcp.json to point at it. The new rules take effect immediately on the next tool call.
_replace flag: "cmd_allow_replace": true. This prevents unexpected accumulation of rules across layers.
This section covers two different tool groups. confirm_action and get_execution_result are available in both editions, but only do anything once confirm_mode: "relay" is configured — see §05. They play no role in plan_only mode, and none in operator_pipe mode either: execute_plan blocks and returns directly there, so there is nothing pending for either tool to act on. verify_policy and verify_audit_log require the Enterprise edition binary; calling them on a Standard installation returns a clear structured error — not a crash or silent failure — mirroring the binary's own behaviour. Call get_version first to confirm edition and which tools are meaningful before attempting any of these.
At startup, the server calls --version on both binaries and parses the output for the word "standard" or "enterprise". The result is cached for the session. If both binaries report different editions, "enterprise" takes priority. If neither binary is found, the edition is "unknown" and Enterprise-only tools return an error. The get_version response always shows the detected edition and which features it enables.
The two tools below exist for relay mode, where this server generates its own private FIFO pair, launches aishell-gate-exec against it, and plays both ends itself: it reads the confirmation request off the FIFO — including, for a typed level, the raw challenge code — and hands it to Claude, which is trusted to show it to the operator and carry their real answer back to confirm_action. Nothing in that path is independently verifiable; an agent could in principle answer confirm_action itself without a human ever seeing the request. operator_pipe mode removes this server from that role entirely. execute_plan instead makes one ordinary blocking call to aishell-gate-exec with --confirm-pipe pointed at a FIFO pair an aishell-gate-confirm session already owns on the operator's own terminal. This server never creates, opens, or reads those FIFOs — it only waits for aishell-gate-exec to exit. Claude is never shown the confirmation request or the challenge code, so confirm_action and get_execution_result have nothing to do in this mode. See §05 to configure confirm_pipe.
Submit a human confirmation response to a waiting execute_plan relay. Call this after execute_plan returns status: "pending_confirmation". The response is forwarded to aishell-gate-exec via a FIFO pair this server creates and reads itself — internal to this process, and distinct from the operator-owned FIFOs used by the SSH relay (aishell-gate-confirm, --confirm-pipe, --confirm-lock). Only active when confirm_mode is "relay" in aishell-gate-mcp.json — available in both editions. Not used when confirm_mode is "operator_pipe", which talks to the real operator-owned FIFOs directly instead — see §05.
execution_id (required) — the token returned by execute_planresponse (required) — "yes" or "no" for action-level confirmation; the exact challenge code for typed confirmationaccepted — boolean; true if the response was valid and forwardedexecution_id — echoed back for trackingmessage — next step guidancetyped, the confirm_request field from get_execution_result contains a challenge code derived from the command text. The operator must type this code exactly — copy it precisely. A mismatch is treated as refusal. This is intentional friction: it forces the operator to visually confirm the exact command before it runs.
Retrieve the current status or final result of an async execute_plan relay. Call after confirm_action to get the outcome, or to check whether further confirmations are required — a plan may have multiple actions each requiring separate confirmation. Only active when confirm_mode is "relay" in aishell-gate-mcp.json. Not used when confirm_mode is "operator_pipe" — execute_plan already returns the final result directly there.
execution_id (required) — the token returned by execute_planstarting — exec process is launchingrunning — exec is running commands, no confirmation needed right nowpending_confirmation — waiting for a confirm_action call; confirm_request field contains full action details including command, risk score, blast radius, and challenge code if applicablecomplete — execution finished; full result is included in the responseRun a JSON policy test suite against the active policy and report PASS or FAIL per test case. Each test case states a command and the expected decision — "allow" or "deny". If reality matches expectation, the case passes. This is a verification tool, not a discovery tool: you already know what the policy should do, and you are confirming it still does so after a change.
tests (required) — list of test case objects, each with:
cmd (required) — the command to evaluateexpected (required) — "allow" or "deny"label (optional) — human-readable description for outputpreset (optional) — override the active preset for this case onlypreset (optional) — active preset for all cases that do not specify their ownall_passed — boolean; true only if every test case passedtotal, passed, failed — countsresults — per-case array with "PASS" or "FAIL" and the output lineexit_code — 0 = all pass, 1 = any fail, 2 = file or parse errorraw_output — the full text output from the policy binaryevaluate_command is a discovery tool — it tells you what the policy does to a command you are exploring. verify_policy is a verification tool — it tells you whether the policy behaves the way you have specified it should. Each test case is evaluated independently with no relationship between commands.
Commit a test suite file alongside your policy override files. After any policy change, call verify_policy with your test cases. If all_passed is false, the change broke a specified expectation — find and fix the regression before deploying. The exit_code field (0 / 1 / 2) maps directly to CI pass/fail conventions.
Verify the HMAC-SHA256 chain integrity of an audit log file. Detects any gap, truncation, reordering, or post-hoc modification. Each audit log entry is linked to the previous by an HMAC of its content — breaking the chain requires either the key or knowledge of every previous entry. This tool runs the correct verifier binary for the log type you specify.
log_path (required) — absolute path to the audit log file to verifylog_type (optional) — "exec" (default) or "policy"chain_intact — boolean; true means no tampering detectedoutcome — human-readable result stringexit_code — 0 = chain intact, 1 = tampering detected, 2 = file errordetail — per-entry report from the verifier binarykey_used — whether an HMAC key was used for verificationThe executor and policy engine write logs in incompatible internal formats. Exec logs use the chain_hmac field and are verified by aishell-gate-exec --audit-verify. Policy logs use the entry_hash field and are verified by aishell-gate-policy --audit-verify. Passing the wrong log to the wrong verifier produces an error or a false broken-chain result. The log_type argument selects the correct verifier automatically.
Set audit_key in aishell-gate-mcp.json to the path of your key file for keyed HMAC verification. Without a persistent key, the binary uses a per-session ephemeral key and cross-session chain verification is not possible. Key file formats differ between the two binaries — see the Configuration section.
aishell-gate-exec invocation is an independent process with its own in-memory chain state. When multiple sessions write to the same log file, the file contains one internally consistent chain per session_id. Verify chains per session_id rather than treating the entire file as a single linear sequence.
config_summary.preset in the response. Confirm the active preset is appropriate for the current workflow.config_summary.audit_log and config_summary.audit_key_set.overall_decision and summary.max_confirm.guidance string to the user. Remove or replace denied commands and re-evaluate.action or typed and confirm_mode is plan_only, inform the operator — execution is blocked. They must either lower the confirm level in their policy file, run those commands manually, or switch to relay mode.overall_decision is "allow" and max_confirm is "none" or "plan", call execute_plan with the same goal and commands.executed and exit_code in the response. Surface outcome and stderr_tail to the user if execution failed.confirm_mode is set to "relay" in aishell-gate-mcp.json. Call evaluate_plan first — confirm the plan is allowed by policy and note which actions require confirmation.status: "pending_confirmation" and an execution_id. Execution is running asynchronously in the background.execution_id. If status is pending_confirmation, the confirm_request field contains the full action details — command, risk score, blast radius, reason, and challenge code if applicable. Present this to the operator.execution_id and the operator's response — "yes" or "no" for action-level, or the exact challenge code for typed confirmation.pending_confirmation, another action needs approval — repeat steps 3–4. When status is complete, the full execution result is returned and the execution is removed from the pending queue.confirm_mode is set to "operator_pipe" and confirm_pipe points at a basepath in aishell-gate-mcp.json. The operator must already have their own aishell-gate-confirm session running against that same basepath — start it before the first execute_plan call, not after.pending_confirmation status and no execution_id. The operator sees the full request (and, for typed levels, the challenge code) directly on their own terminal, exactly as in the SSH deployment.confirm_path: "operator_pipe", plus the usual executed / exit_code / outcome fields. Exit code 2 means the operator refused (or the request timed out unanswered). Nothing further to call — confirm_action and get_execution_result are not part of this flow.confirm_pipe basepath with no aishell-gate-confirm session attached just waits out confirm_timeout (or exec's own 120s default) with nobody to answer it, then returns exit code 2. This is expected — it is not a bug in this server — but it means execute_plan can take a couple of minutes to return an error in that situation rather than failing fast.assessment.reason and assessment.layer — these identify exactly which rule and which policy layer caused the denial.assessment.flag_assessment for per-flag analysis. Flags marked danger or warn show the specific reasoning for any confirmation escalation.cmd_allow rule for the specific command pattern and save as an override file.aishell-gate-mcp.json under policy_project or policy_user. Re-evaluate the command to confirm the rule takes effect.template JSON to a file.cmd_allow, cmd_deny, arg_rules, path_rules, or net_rules. Use _replace: true flags to replace lists entirely rather than appending.policy_project in aishell-gate-mcp.json at the new file. The change takes effect on the next tool call — no restart required.all_passed: true. If any case fails, review the failed case detail and adjust the rule. On Standard edition, use evaluate_command against each case manually instead.A shell script is a sequence of commands toward a goal. So is an AIShell-Gate plan. The difference is everything that happens between the commands and the kernel.
A shell script carries implicit trust — whoever wrote it is assumed to have gotten it right. There is no policy layer, no risk assessment, no mandatory confirmation, and no tamper-evident record of what ran. The script and the shell are a single execution path with nothing in between.
When an AI builds a plan and submits it through the MCP, the structure is the same — a sequence of commands toward a stated goal — but the execution path runs through the policy engine first. Every command is evaluated, risk-scored, assigned a confirmation level, and logged before a single byte reaches the kernel. The AI is doing what a script author does. The environment is fundamentally different from what a shell provides.
A plan submitted through evaluate_plan is inspectable before it runs. The goal is stated, every action is listed, and the policy engine's assessment of each one is available before the operator commits to execution. A shell script is opaque until it runs.
Policy is external and declarable. A shell script embeds its own permissions implicitly — whatever the executing user can do, the script can do. An AIShell-Gate plan runs against a declared policy stack that is versioned, auditable, and independent of the plan itself. The same plan submitted under a stricter policy produces a different outcome without changing a line of the plan.
The audit record is tamper-evident. Shell history is not. In the Enterprise edition, every plan evaluation and execution is HMAC-chained — a verifiable record that cannot be silently modified after the fact.
Confirmation gates are structural. A destructive shell script runs. A plan with a destructive action stops at the appropriate confirmation level and requires explicit operator acknowledgement before proceeding. The gate is not advisory — it is enforced by the executor.
Shell scripts compose. They pipe the output of one command into the input of the next. They branch on exit codes. They loop. They handle intermediate state inline. A shell script that checks the output of git status before deciding whether to run git push is straightforward to write and straightforward to read.
The plan model is sequential and flat. Commands in a plan are evaluated independently — there are no conditionals, no loops, no pipes, and no shell metacharacters. Each command is a discrete action. For workflows that depend on intermediate output to decide what to do next, the plan model does not replace a shell script. The right approach in those cases is to break the workflow into plan segments, evaluate intermediate results in the calling environment, and submit subsequent plans based on what was returned.
For teams already using Claude Code to generate shell commands, the MCP path requires no change in how they think about the problem. The AI still proposes a sequence of commands toward a goal. The difference is that the sequence now passes through a policy gate, gets confirmed at the appropriate level, and produces an audit record. The cognitive model is identical. The execution environment is safer.
All binary stdout is scanned for the first { character before JSON parsing. Any text that precedes the opening brace is silently discarded. This is called the preamble guard.
A binary could in principle write text to stdout before its JSON response — for example, a warning banner from a future version, a custom build, or an unusual deployment scenario. If any such text precedes the JSON object, a naive json.loads(stdout) call will fail with a parse error, making the MCP server appear broken when the binary is working correctly. The guard exists as defensive programming against that possibility, not because the current binaries write any such preamble — it makes the server resilient regardless of what a binary writes before its JSON output.
The guard runs at three points — every location where the server calls json.loads() on binary stdout:
--dry-run-json output from aishell-gate-exec--dry-run-json output before live execution--json output from aishell-gate-policyThe get_policy_template tool is not subject to the guard because it already scans for the first { line by design — the template output has a documented plain-text header block before the JSON body.
If the guard finds no { in the binary output at all, it returns a structured error response rather than crashing:
This makes the failure diagnosable from within Claude Code without inspecting server logs. The stderr snippet in the message typically reveals whether the issue is a missing binary, a license problem, or an unexpected runtime error.
_strip_preamble() before every json.loads() on binary stdout, and pass the stderr string so the error message is informative.
The server could not find or run one of the binaries at startup. Check that exec_binary and policy_binary in aishell-gate-mcp.json point to the correct locations, or that both are on PATH. Run each binary with --version directly to confirm they are executable.
The binaries are not reachable from the working directory the MCP server started in. Use absolute paths in aishell-gate-mcp.json rather than relative paths, or install the binaries to a system PATH location.
The executor ran but wrote nothing to stdout. This usually means a startup security check failed — the binary refuses to run as root, or the binary itself has setuid or setgid bits set. Check the stderr field in the error response for the specific check that failed.
One or more commands in the plan require confirm level action or typed. These cannot be satisfied through the MCP interface. Options: lower the confirm level for the specific commands in a policy override file, break the plan into smaller pieces that exclude those commands, or run the high-risk commands manually at the terminal.
The audit log has been modified, truncated, or reordered since it was written. If you are using an ephemeral key (no audit_key configured), cross-session verification is not possible by design — each session generates its own key. For reliable cross-session verification, configure a persistent audit_key file before the first session that should be verifiable.
The installed binary is the Standard edition. verify_policy and verify_audit_log require the Enterprise edition binary. Call get_version to confirm which edition is installed before attempting either of them. Contact www.aishellgate.com for Enterprise licensing.
Claude Code must be restarted after changes to .mcp.json. Ensure the Python 3 interpreter path is correct and that the script is executable. Run the server manually in a terminal to confirm it starts without error: python3 /path/to/aishell-gate-mcp --version.
Pass --debug to the server to enable verbose stderr logging. In Claude Code, stderr from MCP servers is typically available in the developer console or log output. Debug output includes binary invocations, response sizes, preamble strip events, and edition detection results.
plan_only, relay, or operator_pipe confirm mode)relay confirm mode)read_only, dev_sandbox, ops_safeci_build, ci_deploy, ci_admin, danger_zoneRun get_version to identify the installed edition. Calling an Enterprise tool on a Standard installation returns a structured error response with a clear message and a link to licensing information — not a crash or an unknown error.