Docs · private trial
Quickstart
Gate0x puts a deterministic policy between an AI agent and its MCP tools. It runs locally; nothing is uploaded and no account is needed. Requires macOS and Node 24+.
Security notice: local approvals are not a security boundary.
REQUIRE_APPROVAL asks you before a call runs, but approvals
are files that any process running as your OS user can write. If an agent has
unrestricted shell access as you (a built-in terminal tool, or any shell-capable MCP
server), it can approve its own requests. Block or approval-gate shell execution,
and treat approvals as a safeguard against mistakes, not against a hostile agent.
node gate0x.js scan flags the obvious cases (GX-APR-001,
GX-APR-002).
The short path (about five minutes)
Use a test setup, not production, and no real secrets. You need Node 24+ and nothing
else: no npm install, no sudo, no PATH or shell-profile changes. Gate0x is one file,
gate0x.js, that you run with node from the folder you
received.
Open the folder in Terminal
You received a ZIP that holds one folder,
gate0x-private-trial-0.1.0-rc.5.
- If that folder already exists (macOS usually unpacks a ZIP for you, often in Downloads), use it. Do not unzip it again.
-
If you only see the
.zipfile, double-click it once in Finder. The folder appears next to it.
Open Terminal, type cd and a space, drag the folder from Finder into the
Terminal window, and press Enter. Then check you are in the right place:
$ node gate0x.js --version
It prints 0.1.0-rc.5. If it says it cannot find the file, you are not in
the folder yet: repeat the drag. Optional: check that the files arrived intact.
$ shasum -a 256 -c SHA256SUMS
1. Scan
$ node gate0x.js scan
Scan lists the MCP servers it found and ends with a ready-made line for each risky one, with that server's real name already filled in.
2. Protect one server
Copy the line Scan printed for the server you want to protect. It looks like the line
below, which is only an example: if Scan found a server called
filesystem, the line is
$ node gate0x.js wrap filesystem --apply
If your server has a different name, do not paste the line above; paste the one Scan printed. The command shows exactly what it will change, asks you to confirm, and writes a backup first. When it finishes it prints what to do next. The first step is to restart your MCP client.
3. Keep Approval Watch open
Open a second Terminal window, type cd and a space, drag the same folder
into it, press Enter, then run:
$ node gate0x.js approvals watch
Leave that window open while you use your agent. When a call needs approval it shows up there (see Approvals in detail). Press Ctrl-C only when you want to stop watching.
4. Look at the audit, and undo
Back in the first window:
$ node gate0x.js audit
To undo everything wrap --apply did, then restart your MCP client again:
$ node gate0x.js wrap --rollback
That is the whole loop. Everything Gate0x prints for a next step uses the same
node gate0x.js ... form, so you can copy it as it is.
How Gate0x is installed (and why there is no install step)
-
Nothing is installed globally.
node gate0x.jsruns the file in place. It does not use npm, your npm configuration or cache, or a writable/usr/local. -
Protect needs a stable file. A desktop MCP client starts your server long
after your terminal command has finished, so
wrap --applycopies this one file to~/.gate0x/bin/gate0x-<version>-<hash>.js(owner-only, never overwritten) and points the config at the copy. It shows you that path first. You can delete the folder you received afterwards. -
No sudo, no root, no shell-profile edits. Everything Gate0x writes is under
~/.gate0xand the one config file you approve, plus a backup next to it. If a command ever asks for sudo, stop and tell us.
Scan in detail
$ node gate0x.js scan
$ node gate0x.js scan --verbose
$ node gate0x.js scan --json
The first shows what was found, what is dangerous, why and what to do.
--verbose adds every finding, launch commands and which config files were
checked. --json is stable output for scripts.
Scan checks the default config locations of Claude Desktop, Claude Code, Cursor,
Windsurf, VS Code, Gemini CLI and Zed. Those locations are not yet verified against
every client version, and --path scans any file. It does not start any
server and never prints secret values. The capabilities it reports are
inferred from names and packages in the config, so treat them as strong
hints, not proof.
Protect in detail
--apply changes one server's entry in one config file:
- it prints the before and after (secrets hidden) and asks you to confirm;
- it writes a timestamped backup next to the file first, and never overwrites a backup;
- it replaces only that entry; every other byte of the file stays identical (comments, formatting and other servers included);
- it validates the result before replacing the file, then replaces it atomically;
-
it refuses symbolic links, malformed or oversized files, remote (URL) servers, and
anything it cannot edit safely. Then
wrapwithout--applyprints the entry so you can edit it yourself.
To see the change without making it, add --dry-run instead of
--apply: nothing is written.
If a server is configured in several clients, Gate0x tells you and you choose with
--client cursor (or claude-desktop,
claude-code, windsurf, vscode,
gemini-cli) or --path followed by the config file. Restart
the MCP client afterwards. The entry uses absolute paths to node and the
stable copy of gate0x.js, because desktop clients do not inherit your
shell PATH; if you later change Node versions, roll back and apply again.
Policy
wrap --apply creates a starter policy at
~/.gate0x/policy.json if you do not have one; add
--strict to create the strict starter instead.
- balanced (default): blocks destructive database statements and asks for approval for shell commands, deleting data, payments, credential access, privileged administration, deploys, outbound messages, tools whose definition changed, and calls Gate0x could not fully inspect. Everything else runs.
- strict: asks for approval for anything that is not clearly read-only.
How well does the classification hold up? On a hand-made set of realistic tool names it had never seen, the balanced policy stopped about 7 in 10 dangerous calls and interrupted about 1 in 14 harmless ones. The strict policy stopped all of them but also asked about roughly half of the harmless ones. Expect misses with balanced and some approval fatigue with strict.
$ node gate0x.js policy test ~/.gate0x/policy.json --tool delete_note
$ node gate0x.js policy check ~/.gate0x/policy.json
Approvals in detail
When a call needs approval, the proxy holds it (up to 120 seconds) and says so on stderr. Approval Watch (short path, step 3) shows it like this:
ACTION REQUIRES APPROVAL
Tool:
notes.delete_note
Arguments:
{"id":"n1"}
(secret values are redacted)
Reason:
Deleting or destroying data requires approval.
Expires:
in 120 seconds, at 14:03:09. No answer means denied.
[A] Approve once
[D] Deny
Choice:
Type A to approve exactly this one call, or D to deny it,
then press Enter.
-
Only
A(ora) approves and onlyD(ord) denies. Enter alone does nothing, and anything else is not accepted: it explains the choices and asks again. - If nobody answers, the call is denied when the time is up and the agent is told so.
-
If the arguments are too long to show in full,
Ais not enough: you are asked to typeAPPROVEas well, because you cannot see everything the call would do.
Other ways to answer, if you prefer:
$ node gate0x.js approvals
$ node gate0x.js approve
$ node gate0x.js deny
These list what is waiting, approve the single waiting request (asks you to confirm), and deny it. Nothing is approved automatically: Approval Watch needs an interactive terminal. An approval is bound to the exact call and can be used once. At most 25 requests can wait at a time. Remember the notice above: this is a safeguard against mistakes, not a security boundary.
Audit in detail
$ node gate0x.js audit
$ node gate0x.js audit --verify
The first shows recent decisions and approvals (an answer of D is
recorded as outcome=denied, an unanswered request as
outcome=timeout). The second checks the tamper-evident hash chain.
State lives in ~/.gate0x (owner-only): the audit log, pending approvals,
pinned tool fingerprints and your policy. Arguments are redacted before they are
written (best effort).
If the audit log cannot be written, Gate0x does not run what it cannot record:
-
BLOCKandREQUIRE_APPROVALcalls never run without their record, and high-risk calls never run without a record. -
Low-risk allowed calls are also blocked by default (
--on-audit-failure block). To keep them flowing during an outage, opt in with--on-audit-failure allow-low-risk; the gap is counted and written to the log as anaudit_gapentry once writing resumes.
Policy reference
{
"id": "my-policy",
"version": 1,
"defaults": { "noMatch": "ALLOW" },
"rules": [
{
"id": "block-big-transfers",
"decision": "BLOCK",
"match": {
"category": "payments",
"when": [ { "field": "arguments.amount", "op": "gt", "value": 10000 } ]
},
"reasonCode": "TRANSFER_TOO_LARGE",
"reason": "Transfers over 10,000 are blocked."
}
]
}
Decisions are ALLOW, BLOCK or REQUIRE_APPROVAL.
When several rules match, the most restrictive wins; ties go to the lowest rule id;
rule order never matters. If no rule matches, defaults.noMatch applies
(BLOCK when unset). Rules match on source,
action (server.tool), tool,
resource and category (a string or list; exact or ending in
one *; case and invisible characters ignored). Categories:
filesystem_write, filesystem_delete,
shell_exec, network_egress, messaging_send,
credential_access, payments, db_write,
db_destructive, data_delete, privileged_admin,
deploy_publish.
match.when is a list of conditions that must all hold, each with a
field (arguments.<path> or
context.<path>), an op (eq,
ne, in, prefix, contains,
gt, gte, lt, lte,
within, exists) and a value. A missing field or
wrong type makes the condition false. For paths use within, which
resolves ..; prefix does not.
Known limits
Read these before relying on Gate0x for anything.
- Local approvals are not a security boundary (see the notice at the top).
-
Coverage is narrow. Protect checks
tools/callfor local stdio MCP servers only. It does not see remote (URL) servers, MCP resources or prompts, or an agent's built-in tools (for example a built-in terminal). - Classification can miss dangerous tools. It is a keyword heuristic over names, descriptions, argument names and SQL or shell text. It misses tools with unusual names and does not decode encoded commands.
-
It only sees what goes through it.
node gate0x.js scanshows which servers are not protected. - The audit log is tamper-evident, not tamper-proof. Edits and middle deletions are detected; removing the newest entries is not.
- macOS first. Linux has automated test coverage only; Windows is not supported.
- Single machine. No central management, sync or hosted dashboard.