The AIShell-Gate MCP server exposes the policy engine and execution gateway to Claude Code, Cursor, and any MCP-compatible AI environment. Eight tools. Two editions. One configuration file. This document covers installation, configuration, every tool, common workflows, and the robustness design that keeps evaluation-copy warnings from corrupting responses. There is also something unexpected here: a plan built by an AI and submitted through the MCP is, in a meaningful sense, a policy-governed alternative to shell scripting — auditable and confirmable in ways a shell script never could be.
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 eight tools. Six 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 before any command touches the system.
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.
Run a test suite of command/expected pairs. PASS/FAIL per assertion. Regression testing after policy changes.
Resolved operator overlay layers as JSON — base, project, and user overrides. Enterprise only. The standard_policy layer and built-in command/flag catalog are not included.
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 §08 →
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-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 eight tools will appear in the available tool list. Use get_version to confirm the connection and edition.
The server reads aishell-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. Values: read_only, ops_safe, dev_sandbox, 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 | null | Path to the base policy override file. Applied below preset in evaluation order. |
| policy_project | 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. |
| 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, raw, web, unknown. |
| 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. |
ci_build and ci_deploy presets are designed for unattended pipelines and require --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-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 six tools are available in both Standard and Enterprise editions. 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-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. Plans where any action requires confirm level action or typed are blocked — these require a human operator at the terminal, which cannot be satisfied through the MCP interface.
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 only if all actions ran successfullyexit_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 executionnone or plan can proceed through the MCP. Commands at action or typed cannot — they require a human operator at a terminal. If execute_plan is blocked for this reason, the response lists the specific commands that require confirmation so the operator can either lower the confirm level in their policy file or run those commands manually.
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. Values: read_only, ops_safe, dev_sandbox, 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-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.
Run 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.
These two tools 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 before attempting enterprise tools.
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 all enterprise tools return an error. The get_version response always shows the detected edition and which features it enables.
Dump the operator-supplied policy overlay layers as JSON via --dump-policy. The output reflects the base, project, and user override layers — the rules you have added on top of the standard policy. The standard_policy layer and the built-in command/flag catalog are intentionally omitted; they constitute proprietary AIShell Labs intellectual property. To inspect how the engine evaluates a specific command, use evaluate_command or evaluate_plan — those return the full per-command decision including which rule and layer matched.
preset (optional) — which preset stack to dump. Defaults to the active configured preset.policy — the JSON dump from --dump-policy, including:
overlay_layers — array of operator-supplied layer objects (base, project, user) each with their cmd_allow, cmd_deny, arg_rules, path_rules, net_rules. Empty layers are omitted.preset, default_deny, net_default_deny, versionnote — explains what is omitted and directs to evaluate_command for decision inspectionWhen verifying that an override file was applied correctly — that your custom rules appear in the expected layer with the expected values. When conducting a security review of operator-added rules. For inspecting why a specific command was allowed or denied, use evaluate_command instead — it returns the matched rule, layer, risk score, and reason directly.
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-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, inform the operator — execution through the MCP is not possible for those actions. They must either lower the confirm level in their policy file or run those commands manually.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.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-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-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.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.
Evaluation copies of AIShell-Gate write a banner to stdout before the JSON response — for example, an expiry warning such as "Evaluation copy — expires in 23 days." If this 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 was added not because the binaries misbehave, but because future binary versions, custom builds, or deployment scenarios could introduce preamble text in stdout without the MCP developer expecting it. The guard makes the server resilient regardless of what a binary writes before its JSON output.
The guard runs at four 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-policy--dump-policy 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-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-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. dump_policy and verify_audit_log require the Enterprise edition binary. 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.
Run 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.