zn-gate
OfficialProvides a Python package with a rules engine and secret redaction for agents built with CrewAI, helping keep secrets out of model inputs and checking tool calls for prompt injection.
Works as an MCP server in JetBrains IDEs, adding security checks for tool calls and secret redaction to protect coding agents.
Provides a Python package with a rules engine and secret redaction for agents built with LangChain, helping keep secrets out of model inputs and checking tool calls for prompt injection.
For: developers using Claude Code, Codex CLI, Cursor, OpenCode or any MCP client, and teams building agents with MCP, LangChain, CrewAI or LlamaIndex.
What it does: keeps secret values out of what your agent sends to its model, checks what your agent reads and calls for prompt injection, and audits prompts, skills and configs. Everything runs on your machine, is MIT-licensed and needs no account. The Python package has no runtime dependencies; the npm package's only one is age-encryption (with its @noble/@scure dependencies) for the secret vault, bundled in the package.
Install
Everything runs on your machine; no account or API key is needed. You need Node.js 18 or later (the LTS version from nodejs.org). With an older Node.js, the zn-gate and zn commands stop and say how to install it. The Claude Code plugin needs Node.js 20.12 or later.
Getting started: four steps, one command each. Run them in your own terminal.
npx -y zn-gate reachshows what your coding agents can reach on this machine: secrets in your.envfiles (by name only), credential files and MCP servers. It is read only and sends nothing. Details in docs/reach.md.npx -y zn-gate initsets up protection for the coding agents it finds, one step at a time, and asks before each change.npx -y zn-gate checktests that protection with a fake secret in a temporary folder.initruns it at the end too.npx -y zn-gate env shadow .envmoves the real values of your.envinto the local vault and leaves markers in the file. The first time, runnpx -y zn-gate unlockto create the vault.
One command for the coding agents on your machine:
npx -y zn-gate initIt finds Claude Code, Codex CLI, Cursor and OpenCode, shows the setup for each one that is not protected yet (the zn-gate plugin for Claude Code, zn's hooks for the others), runs each step after you confirm it, and ends with zn-gate check. Run it yourself in your own terminal, with no arguments: when an AI agent or a script runs it, it only prints the steps.
Windows PowerShell:
npmandnpxcan fail with "running scripts is disabled on this system", because the default execution policy blocksnpm.ps1. Usenpm.cmd,npx.cmdandzn.cmdinstead (for examplenpm.cmd install -g zn-gate), run the commands from Command Prompt, or allow local scripts for your account withSet-ExecutionPolicy -Scope CurrentUser RemoteSigned.
Then keep your .env values in the vault. With the plugin or the hooks, the agent cannot read .env files with real values; move them into zn-gate's encrypted vault, and the file keeps markers such as __ZN_STRIPE_KEY__:
npx -y zn-gate unlock # creates the vault the first time
npx -y zn-gate env shadow .envAfter this, your own app also reads the markers in .env: start it with zn-gate's run command once you allow it (docs/secrets.md). env shadow tells you how to undo it.
Five-minute walkthrough: docs/secrets.md. Limits: docs/threat-model.md.
One agent at a time (the same steps init runs):
Claude Code: the plugin. You also need Git and Claude Code 2.1.295 or later.
claude plugin marketplace add usezn/zn
claude plugin install zn-gate@useznAlready ran zn hooks install claude-code before? Run zn hooks uninstall claude-code first, otherwise both sets of hooks run.
Start a new Claude Code session. Claude Code is then blocked from reading .env files with real values and credential files, secrets in what its tools return are replaced with markers or redacted before the model sees them, a secret pasted into a prompt is blocked, and Claude can check untrusted text for prompt injection. Not covered: Claude Code sessions in the cloud, Cowork and chat. Details: plugins/zn-gate.
Codex CLI, Cursor or OpenCode: the hooks.
npm install -g zn-gate
zn hooks install codex # or: cursor, opencodeIn Codex, approve the new hooks with /hooks. In Cursor, shell output and file contents are not scrubbed. What each agent supports: docs/compat.md.
Other editors (VS Code, Antigravity, Windsurf, Cline, Zed, JetBrains, Continue): zn-gate works there as an MCP server only. Setup for each one: usezn.com/docs/integrations/editors.
Python: for agents you build yourself (rules engine and secret redaction for LangChain, CrewAI, LlamaIndex or plain tool calling). It does not protect Claude Code, Codex, Cursor or other coding agents. Install it in a virtual environment; many recent Linux systems, and Homebrew's Python on macOS, refuse pip install outside one ("externally-managed-environment"):
python3 -m venv .venv
.venv/bin/pip install zn-gate # Windows: .venv\Scripts\pip install zn-gateOn Debian and Ubuntu, python3 -m venv needs the python3-venv package first: sudo apt install python3-venv.
zn-gate as an MCP server only (the agent calls it when it decides to; not automatic protection):
claude mcp add zn-gate -- npx -y zn-gate mcp # Claude Code
codex mcp add zn-gate -- npx -y zn-gate mcp # Codex CLICursor (~/.cursor/mcp.json) and other editors: { "mcpServers": { "zn-gate": { "command": "npx", "args": ["-y", "zn-gate", "mcp"] } } }. OpenCode (~/.config/opencode/opencode.json): { "mcp": { "zn-gate": { "type": "local", "command": ["npx", "-y", "zn-gate", "mcp"], "enabled": true } } }.
Protect the MCP servers you already use. init finds them in your agent configs, writes a backup, and wraps each local server with the zn-gate proxy:
npx -y zn-gate init --dry-run # preview
npx -y zn-gate init --wrap-mcp # wrap (backup first)
npx -y zn-gate init --revert # undoIt reads Claude Desktop, Claude Code (~/.claude.json), Cursor (~/.cursor/mcp.json), Codex CLI (~/.codex/config.toml), OpenCode (~/.config/opencode/opencode.json) and Antigravity (~/.gemini/antigravity/mcp_config.json). Full list and rules.
Related MCP server: Bulkhead
Check that it works
npx -y zn-gate checkFor each agent set up for your user, zn-gate asks its hook to let the agent read a .env file with a fake key and an ordinary file, in a temporary folder. It shows what your agent would be told, and a line that says NOT protected says how to fix it. Nothing is sent over the network and no setting changes. What the output means.
npx -y zn-gate testThis runs the local self-test (51 curated vectors: 26 attacks, 25 benign) and shows per-decision latency on your machine. It is a smoke test, not a detection rate. Nothing is sent over the network.
For developers: see the redaction by hand. Send a tool output with a fake AWS key (AWS's documentation example) and a database password through zn-gate, exactly as your agent would, and look for sanitized_content in the output; that field is what the model would see:
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"check_tool_result","arguments":{"tool_name":"read_file","content":"AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE\nDATABASE_URL=postgres://app:hunter2@db:5432/main"}}}' \
| npx -y zn-gate@latest mcpPython equivalent:
.venv/bin/python -c "from zn_gate import sanitize_tool_result as s; print(s('read_file', 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE')['sanitized_content'])"What each piece does
Where zn-gate sits in a tool call, as an MCP server or as the shield proxy around other servers:
Scrubber: secrets stay out of the model's context
Today, through zn-gate: redacts AWS keys, OpenAI and Anthropic keys, GitHub tokens, JWTs, private keys and database URL passwords in everything that passes through zn-gate: tool output checked with
check_tool_result, tool arguments checked withcheck_tool_call, and output of MCP servers wrapped byzn-gate shield/init. Python:sanitize_tool_result,@guard(mask_secrets=True)and the framework integrations.Today, agent hooks and vault (npm package): hooks for Claude Code, Codex CLI and OpenCode scrub the output of the agents' built-in tools and block pasted secrets (in Cursor only MCP tool output is scrubbed); a local encrypted vault with stable markers (
__ZN_AWS_KEY_1__);zn runfills values only into commands you approved; personal data (cards, IBAN, national IDs, e-mail, phone) is detected too. What each agent allows differs: see docs/compat.md.
Galvanize: prompt-injection detection
Today, local: a deterministic rules engine (signatures plus normalization against homoglyphs, zero-width characters, BiDi overrides, comment splicing and Base64) checks prompts, tool arguments, tool output and MCP tool descriptions.
Today, optional cloud check: the Galvanize 2 classifier (open weights on Hugging Face, Apache-2.0) can also check prompts sent to
analyze_prompt, only if you setZN_CLOUD=1andZN_API_KEY. The secrets zn-gate detects are removed from the prompt on your machine before it is sent; personal data is not removed on this path.Roadmap: running Galvanize locally inside zn-gate.
Scan: audit what your agent is about to trust
Today:
zn-gate scan <path>audits prompt templates,AGENTS.md/SKILL.mdfiles and configs for injection traps and leaked secrets (exit code 1 on findings, for CI). A leaked secret is reported as Secret found, with the next step:npx -y zn-gate env shadow <file>moves the values of a.envfile into the local vault,npx -y zn-gate secret set NAMEstores any other one. It finds provider keys and tokens, opaqueAuthorization: Bearertokens, passwords in URLs, and secrets passed as command-line flags (--token=...) or assigned to a name such aspasswordorapi_key. The same check runs as a GitHub Action. MCP servers can be checked on the web at usezn.com/scan.Roadmap: auditing MCP servers and skills from the CLI before you add them.
What the cloud adds for teams
Everything above runs locally, for free, with no account. The optional cloud at usezn.com is for teams that need a shared record of what their agents did:
Audit and traceability: an evidence dashboard with the metadata of each cloud decision (verdict, rule, score, latency), 90-day retention and CSV/JSONL export.
A larger detection model for prompts, when you opt in (
ZN_CLOUD=1).Team controls (shared policies, organization-level audit): in progress.
By default nothing is sent. If you set ZN_CLOUD=1 and an API key (or the API key option of the Claude Code plugin), analyze sends the prompt text after removing the secrets zn-gate detects locally: personal data is not removed on this path, and a secret it does not detect would be sent with the text. The dashboard keeps the metadata of each cloud decision. Tool output and tool-call arguments are never sent.
What leaves your machine
Nothing, by default.
Data | Evaluated | Sent anywhere? |
Tool output ( | Locally | Never, in any configuration |
Tool-call arguments ( | Locally | Never, in any configuration |
MCP tool and parameter descriptions ( | Locally | Never, in any configuration |
Counts of what zn-gate did ( | Written locally to | Never, unless you turn on |
Prompts ( | Locally | Only if you set both |
ZN_API_KEY alone enables nothing. ZN_LOCAL_ONLY=true overrides ZN_CLOUD=1. npx -y zn-gate status prints what your configuration sends.
1.4.0 and earlier: with
ZN_API_KEYset, the Node package sent tool output and tool-call arguments toapi.usezn.comwithout redaction. 1.4.1 removes that path. Details in the CHANGELOG.
Performance and accuracy
We only publish numbers we can reproduce, with the method next to them.
Latency of the local engine: one table by input size, with hardware, date and the script to reproduce it (
bench/bench_by_size.js), in the npm package README. Short summary from that run, with secret redaction (p50): about 0.045 ms for a 200 B prompt, 0.3 ms for a 4 KB tool output, about 4 ms for 64 KB.Self-test: 51 curated vectors pass. That is a smoke test, not a detection or false-positive rate.
Known limitation: on whole source files, the rules can flag ordinary code comments. Version 1.5.0 reduces these on code and documentation, at the cost of letting some loosely worded override attempts through the local rules. To check it on your own source files, run
zn-gate scan --code <path>; for the MCP servers you wrap,--shadowlogs detections without blocking.Known limitation: detection of credentials under prefixed variable names (e.g.
OPENAI_API_KEY=) is partial in this release.Detection rates: on a private held-out set of 3,309 examples, Galvanize 2 has 83.4% recall at a 0.81% false positive rate (serving threshold 0.662); these numbers are for the cloud classifier, not the local rules engine. Method, per-language results, known weak spots and a reproducible benchmark are in the model card and the announcement. It is one layer of defense, not a guarantee.
Configuration
Variable | Default | Effect |
| off |
|
| unset | API key from usezn.com/dashboard. No effect without |
| unset |
|
|
| Cloud endpoint selection. |
zn Team: zn team join <token> connects a machine to your organization's signed secrets policy and uploads its audit log (metadata only). What the organization can and cannot change on the machine, offline behavior and the OpenTelemetry export (zn vault log export --otlp): docs/team.md.
Custom rules: add banned patterns and forbidden paths in .znrules or zn.config.json at your project root (example).
Audit log: zn-gate shield appends each decision to ~/.zn/evidence.jsonl as a hash-chained (SHA-256) record with a redacted preview. It detects accidental or partial edits; it is not tamper-proof against someone with write access to the file. Check it with npx -y zn-gate evidence --verify.
GitHub Action
The action installs the published zn-gate packages at an exact version and runs on the runner only; it sends nothing anywhere. It has two checks, chosen with mode:
scan(default):zn-gate scanlooks for prompt-injection traps and leaked secrets in prompts, tool definitions and config files (Python package from PyPI). This is what earlier releases of the action did.audit:zn auditreviews what your coding agents are configured to trust:.claude/,.mcp.json,.codex/,.cursor/, hooks,AGENTS.md/CLAUDE.md, plugins and skills (npm package; needs version 1.6.0 or later).both: runs the two. With aversionolder than 1.6.0, or a PyPI-only.postversion, it runs the scan only and prints a warning.
Scan prompts on pull requests:
name: AI agent security scan
on:
pull_request:
paths:
- 'prompts/**'
- '**/*.prompt'
- '**/AGENTS.md'
- '**/SKILL.md'
permissions:
contents: read
jobs:
zn-gate-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Scan AI agent prompts and tools
# Pin the action to a full commit SHA; the comment names the release.
uses: usezn/zn@003a95ae7ef63c22b969496422131a49fa107f8d # v1.12.0
with:
version: '1.12.0'
package-sha256: '9e7b7ac4a43722249c10623dcb5817c1cd956b6100d6ca02faa8b6451dd72dbf'
path: '.'
fail-on-threat: 'true'
format: 'github'Audit agent configs and plugins on every pull request, and show the findings in code scanning. The audit takes seconds, so the example has no paths: filter: a filter would skip the configs of agents it does not list.
name: AI agent config audit
on:
pull_request:
permissions:
contents: read
jobs:
zn-gate-audit:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # only for the SARIF upload
actions: read # private repositories only, for upload-sarif
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Audit agent configs
id: zn
# Pin to the full commit SHA of the first Action release that has the
# mode input. The zn-gate package version is set by version below.
uses: usezn/zn@<commit-sha> # <first Action release with mode>
with:
version: '1.12.0'
mode: 'both'
format: 'sarif'
severity-threshold: 'medium' # stricter than the default (high)
- name: Upload SARIF
if: ${{ !cancelled() && steps.zn.outputs.sarif-file != '' }}
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
with:
sarif_file: ${{ steps.zn.outputs.sarif-file }}Input | Default | Description |
|
| Exact |
|
| Requires a release of the action that includes audit mode (see the CHANGELOG). |
|
| File or directory to scan. |
|
| Fail the step on findings. For |
|
| Requires a release of the action that includes audit mode (see the CHANGELOG). Audit only: lowest severity that fails the step when |
| empty | Requires a release of the action that includes audit mode (see the CHANGELOG). Audit only: lowest severity that fails the step ( |
| empty | Requires a release of the action that includes audit mode (see the CHANGELOG). Audit only: comma-separated agents to audit ( |
|
|
|
| empty | Requires a release of the action that includes audit mode (see the CHANGELOG). With |
| empty | Requires v1.5.0 or later of the action. SHA-256 of the PyPI wheel for |
| empty | Requires a release of the action that includes audit mode (see the CHANGELOG). Integrity string ( |
Output | Description |
| Requires a release of the action that includes audit mode (see the CHANGELOG). Path of the SARIF file ( |
| Exit code of the scan: 0 clean (or |
| Requires a release of the action that includes audit mode (see the CHANGELOG). Exit code of the audit: 0 clean, 1 findings at or above |
The scan finds more secret types with each release (1.9.1 added secrets passed as command-line flags and assigned to names such as password or api_key), so a job that fails on findings can start failing on files that passed before: pin version and read the findings before you update it.
Older releases of the action ignore the inputs they do not have, with only a warning: with one of them, mode: audit runs the scan instead.
Which audit findings fail the step: fail-on if it is set; otherwise none when fail-on-threat is false; otherwise severity-threshold. For the scan, only fail-on-threat applies.
With mode: both and format: sarif, the file holds one SARIF run per check (zn-gate scan and the audit's own run), each with its own category, so code scanning tracks their alerts separately. The step fails with the worse of the two results: an error beats findings.
Permissions: the action itself needs only contents: read; add security-events: write to the job only when you upload SARIF (and, in private repositories, actions: read, which upload-sarif needs). Packages are installed without running install scripts or build steps (--only-binary=:all: --no-deps for the wheel, --ignore-scripts for the npm tarball, whose dependencies are bundled) into private directories under the runner temp directory. pip still reads the runner's own pip settings (PIP_* environment variables and pip.conf), so a mirror or proxy you configure there is used; set package-sha256 so that the wheel is checked whatever index it comes from (and npm-integrity for the npm tarball). Run it on pull_request, never on pull_request_target: do not check out untrusted pull-request code in a pull_request_target workflow. With mode: audit or both the action also sets up Node.js 22 for the rest of the job.
Repository layout
packages/zn-gate: Node.js CLI, MCP server andshieldproxy (npm).packages/zn-gate-py: Python SDK and CLI (PyPI).src/: legacy Rust gateway, not released (docs/rust-core.md).bench/: benchmark scripts and results.assets/brand/: logo files (SVG master and light/dark variants, PNG lockup and banners).
FAQ
Do I need an account or API key? No. Everything local works without one. An account is only needed for the optional cloud (team audit and the larger detection model).
Does zn-gate slow my agent down? The local check adds under a millisecond for typical prompts and tool outputs (p99 0.8 ms at 4 KB on our test host). See the measured table above.
Will it block legitimate content? Sometimes. Use init --shadow or shield --shadow to log detections without blocking while you evaluate it.
Which agents are supported? Any MCP client. init can rewrite configs for the agents listed under Install.
How do I remove it? npx -y zn-gate init --revert restores your configs from the backup. For a standalone server, remove the zn-gate entry from your agent config.
Security
Report vulnerabilities to security@usezn.com. Policy, scope and safe harbor: SECURITY.md. Hall of Fame: usezn.com/security.
Releases published by the release workflow, starting with the first one after 1.5.0-beta.1, are signed and carry build provenance. 1.5.0-beta.1 and earlier versions were published by hand and have no signatures or provenance. To check a download: docs/verify-release.md.
Community and support
Discussions: questions about setup and use, ideas, and show and tell. Start here if you are not sure where your question belongs.
Issues: reproducible bugs and concrete feature requests.
Security vulnerabilities: do not post them in Discussions or Issues. Report them privately as described in SECURITY.md.
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md.
License
MIT. Copyright (c) 2026 usezn (usezn.com). The Galvanize 2 and Galvanize-60M weights are Apache-2.0. The zn-prompt-injection-bench dataset is CC-BY-4.0. The npm package bundles third-party code listed in THIRD_PARTY_NOTICES.md.
Available Tools
4 toolsanalyze_promptARead-onlyIdempotent
Analyze text, prompt, or agent messages for security threats (prompt injection, jailbreak, credential exfiltration, role hijacking). Runs locally; only if the user set ZN_CLOUD=1 and ZN_API_KEY is the text, with secrets redacted, also sent to the zn cloud gate. Returns threat assessment, confidence score, and matched rule.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The user input, system prompt, or external message to inspect. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), yet the description still adds real behavioral context the annotations cannot: it runs locally, it only egresses to the cloud gate when ZN_CLOUD=1 and ZN_API_KEY are set, and secrets are redacted before transmission. That data-flow disclosure is exactly what an agent needs before sending sensitive prompts. The sentence is syntactically mangled ('ZN_API_KEY is the text, with secrets redacted, also sent to...'), which blunts the disclosure somewhat.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the detection scope, which is correct, and there is little fat. However, the second sentence crams the local/cloud routing, env-var condition, redaction, and return shape into one run-on clause that is grammatically broken and forces re-reading.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Compensates well for the absent output schema by naming the return payload (threat assessment, confidence score, matched rule), and discloses the privacy/data-flow model. Remaining gaps are minor for a single-string read-only tool: no severity thresholds, no guidance on acting on a low-confidence match.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
One parameter with 100% schema coverage, so the schema already defines 'text' fully; baseline is 3. The description adds marginal value by broadening the accepted input to 'text, prompt, or agent messages', but gives no length limits, encoding expectations, or guidance on chunking large inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (analyze/check) and resource (text, prompt, agent messages) and enumerates the exact threat classes it detects: prompt injection, jailbreak, credential exfiltration, role hijacking. Sibling differentiation is only implicit — the scope wording implies it handles free text rather than tool calls/results, but check_tool_call and check_tool_result are never named, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the resource description (analyze standalone text rather than a tool call or tool result), but there is no explicit 'use this when / use X instead' routing, no prerequisites, and no statement about whether it should be run on every inbound message or only on untrusted input.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_tool_callARead-onlyIdempotent
Pre-flight safety inspection for tool invocations and arguments before execution. Always local: arguments never leave the machine. Defends against tool poisoning, argument injection, and unauthorized exfiltration attempts.
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | Yes | Parameters/payload object that will be supplied to the tool. | |
| tool_name | Yes | The name of the tool to be called (e.g. bash, write_file, execute_sql, send_message). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds genuinely new behavioral context: local-only execution ('arguments never leave the machine') and the specific threat classes it guards against (tool poisoning, argument injection, exfiltration). It does not say what happens on a failed check, which is the remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core purpose and capped by the security rationale. Slightly promo-flavored in the last clause, but every sentence carries information an agent can use.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool's security posture and locality are well covered, and there is no output schema to explain. But for a gate-style check, the description never indicates what a caller receives (verdict, flags, blocking vs advisory), which an agent needs to know to act on the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters, so tool_name and arguments are already well documented. The description adds no syntax, format, or nesting guidance beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action (pre-flight safety inspection) on a specific resource (tool invocations and their arguments) with a clear temporal qualifier ('before execution'). An agent can distinguish it from check_tool_result (post-execution) by timing alone, though the description never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'before execution' gives clear timing context for invocation, which implies when to call it. However, it never states when NOT to use it or points to the sibling tools (check_tool_result, analyze_prompt) that cover adjacent checks, leaving the routing decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_tool_resultARead-onlyIdempotent
Post-execution safety inspection for tool outputs and third-party content (web pages, git commits, database queries) before LLM context assimilation. Always local: content never leaves the machine. Returns the content with secrets redacted, or neutralized if an injection is detected.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The output text, markdown, or JSON payload returned by the tool. | |
| tool_name | Yes | The name of the tool that produced the output (e.g. fetch, web_search, read_file). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, not open world), yet the description adds genuinely new behavioral facts: execution is always local and content never leaves the machine, and the return value is the original content with secrets redacted or neutralized when an injection is found. That transformation/return behavior is not derivable from any structured field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose, then the privacy guarantee, then the return contract. Every sentence carries distinct information and there is no filler or repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing return values and does so (redacted content or neutralized content on injection detection). The remaining gap is the ambiguity of 'neutralized' — the actual returned shape or replacement text is not specified — plus no note on idempotency of repeated checks.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with only two required parameters, both already self-documented in the schema. The description mentions content categories (web pages, git commits, database queries) but adds no syntax, format, or interpretation guidance for 'content' or 'tool_name' beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action (post-execution safety inspection), a specific resource (tool outputs and third-party content such as web pages, git commits, database queries), and a precise timing scope ('post-execution ... before LLM context assimilation'). That timing/scope framing implicitly separates it from the call-side sibling check_tool_call, so an agent can route between them without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states exactly when the tool belongs in a workflow: after a tool has produced output and before that content enters the model's context. However, it names no alternatives (check_tool_call, analyze_prompt) and gives no exclusions or 'when not to use' condition, which is what a 5 would require.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zn_statusARead-onlyIdempotent
Get current zn-gate status: engine, rules version, and exactly what (if anything) leaves the machine.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description still adds real value by promising an egress disclosure — "exactly what (if anything) leaves the machine" — which tells the agent this call answers a privacy question, not just a version lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the resource first and the three returned items listed afterward. Every clause carries information; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, non-destructive status read with no output schema, the description supplies what an agent needs: what is returned and the notable data-egress angle. Annotations handle safety, so nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline applies. The enumerated return fields arguably compensate for the absence of an output schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ("Get") and resource ("zn-gate status") and enumerates the returned fields: engine, rules version, and data-egress disclosure. It is clearly distinguishable from the analyze_/check_ siblings, though it never names them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the inspection/health-check tool rather than a prompt or tool-call validator. There is no explicit statement of when to call it (e.g. before enabling the gate, when diagnosing config) and no mention of alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v1.12.0- First observed
analyze_prompt - First observed
check_tool_call - First observed
check_tool_result - First observed
zn_status
TDQS
Scored across 4 tools
Each tool targets a distinct phase of the LLM pipeline: analyze_prompt handles user/agent input, check_tool_call inspects outbound tool invocations, check_tool_result inspects inbound tool outputs, and zn_status reports configuration. There is no meaningful overlap in purpose or timing, so an agent can select unambiguously.
All names use snake_case and are readable, with check_tool_call/check_tool_result forming a clean parallel pair. The minor deviations are analyze_prompt using a different verb and zn_status using no verb at all, but the convention is still largely predictable.
Four tools is exactly right for a security gate covering the three inspection checkpoints plus a status probe. Nothing is redundant and nothing feels padded or missing.
The surface covers the full lifecycle of a security gate: pre-prompt analysis, pre-execution tool call checking, post-execution result checking, and introspection via zn_status. No obvious operational gap remains for the stated domain.
Maintenance
Related MCP Connectors
The WAF for agents. Pattern-based + heuristic firewall scans prompts, RAG documents, tool argume...
Security scanner for AI agents: prompt injection, leaked secrets, PII, and SSRF-risk URL detection.
Security gateway for AI agents: policy, approval, and audited execution, no secrets shared.
Lets coding agents check their own code for leaked secrets, risky dependencies and AI-code mistakes
Related MCP Servers
AlicenseAqualityBmaintenanceEnables AI agents to scan text for leaked secrets and prompt injection markers, and redact them before reaching an LLM.21MIT- AlicenseNot gradedqualityBmaintenanceProvides cascading content protection for AI coding assistants by detecting and redacting PII, secrets, prompt injection, and system prompt leakage before they reach LLMs.12 npmMIT
- AlicenseNot gradedqualityDmaintenanceLocal-first security check for AI coding agents — finds hardcoded secrets, exposed .env files, git-history leaks and vulnerable dependencies (OSV), entirely on your machine. Ask your agent "is this safe to ship?" and get a Launch Readiness score with a fix for every finding.MIT
- AlicenseNot gradedqualityCmaintenanceScans text and files for common secrets (AWS, GitHub, etc.) and redacts them to prevent credential leakage in AI-assisted development. Runs entirely locally with no telemetry.MIT