CLI reference
18 commands, grouped by what you are trying to do. Flags and usage are printed from the version you have installed.
Start here
scanstatusApprove and protect
baselineapprovedecideguardwrongLook closer
verifypanelrunsdemoWhen something goes wrong
checkupreportSet up and account
install-nodeloginlogoutskillspushExit codes
The same vocabulary across every command, so a script can branch on it.
| Code | Means | Read it as |
|---|---|---|
0 | clean | nothing to act on |
1 | findings | something was found and is reported |
2 | usage | the command was called wrongly |
3 | cannot run | not installed, or the capability is not on this tier |
4 | incomplete | it ran but could not finish, so it is NOT clean |
4 is not 0. A run that timed out or could not reach a server exits 4. "Could not check" and "checked and clean" must never be the same signal to a script.
Start here
Find out what your agents can already reach.
mcpgawk scan
Measure MCP servers on this machine: every tool they expose, what each one costs your context window, and what it can reach. With no argument it reads every agent config it can find. Give it a config path to scan only that client. Local servers are launched only after you say yes, because scanning one means running its code.
usage: mcpgawk scan [-h] [--stdio STDIO] [--http HTTP] [--sse SSE] [--header HEADER]
[--login] [--oauth-client-id OAUTH_CLIENT_ID]
[--oauth-client-secret-env VAR]
[--oauth-redirect-uri OAUTH_REDIRECT_URI] [--only ONLY] [--yes]
[--no-signals] [--no-track] [--json] [--fleet-json] [--with-spec]
[--verbose] [--full] [--detail] [--supply-chain] [--oauth-scopes]
[config]
positional arguments:
config path to an mcp.json config
options:
-h, --help show this help message and exit
--stdio STDIO one stdio server, e.g. "npx -y @modelcontextprotocol/server-
filesystem /tmp"
--http HTTP one streamable-HTTP server URL
--sse SSE one SSE server URL
--header HEADER HTTP header, e.g. "Authorization: Bearer XYZ" (repeatable)
--login for a remote --http/--sse server that needs OAuth: open the browser,
sign in once, and scan (token stored locally in ~/.gawk/oauth)
--oauth-client-id OAUTH_CLIENT_ID
with --login, for a server that REFUSES automatic client
registration (figma, Slack — enterprise posture): use this pre-
registered OAuth client id. Register the pinned redirect URI mcpgawk
prints with the provider first
--oauth-client-secret-env VAR
environment variable holding the pre-registered client's secret
(never passed on the command line; omit for a public client + PKCE)
--oauth-redirect-uri OAUTH_REDIRECT_URI
override the pinned redirect URI (must match the provider's
registration EXACTLY)
--only ONLY comma-separated server names to scan from the config
--yes, -y launch discovered/configured local (stdio) servers WITHOUT the
consent prompt (scanning a stdio server runs its code) — for CI /
non-interactive use
--no-signals skip BOUNDED heuristic signals (facts only)
--no-track do NOT record this scan locally (drift/rug-pull detection is on by
default; history stays on this machine, at ~/.mcpgawk/history.json)
--json emit JSON labels instead of a table
--fleet-json emit the FLEET STATUS as JSON (one row per server, grouped by the
tool it lives in) — what the IDE extension renders, so state is
computed once here
--with-spec with --fleet-json, include each server's launch spec
(command/args/env or url) so a local front-end can verify it by
click — MAY carry secrets from your config; kept off by default and
never printed without this flag
--verbose show the full per-tool table, not just flagged tools
--full print the full per-server surface even when a baseline makes what-
changed the default view
--detail print the full narrative report for EVERY server instead of the
fleet status list (the list is the default when more than one server
is scanned)
--supply-chain opt-in: query the public npm/PyPI registry for the launched
package's deprecation/yank status (network egress — package
name+version only)
--oauth-scopes opt-in: locally decode a supplied Bearer JWT's scope claim (no
network; reads a credential you already provided)mcpgawk status
One answer to 'am I protected'. Read-only — opens nothing, starts nothing. Coverage is reported PER AGENT, never in aggregate: the hook installs into Claude Code only, so a single cheerful tick would tell a Cursor user they are covered when they are not.
usage: mcpgawk status [-h] options: -h, --help show this help message and exit
Approve and protect
Decide what a server is allowed to be, then hold it to that.
mcpgawk baseline
The shared baseline every pillar compares against. `verify` and `monitor` read this so that approving a server once is approving it everywhere, instead of each keeping its own memory and contradicting the others.
usage: mcpgawk baseline [-h] [--json] [--server NAME] options: -h, --help show this help message and exit --json machine-readable (the cross-runtime shape) --server NAME one server (name or alias) instead of all
mcpgawk approve
Accept a server's current tools as the baseline you trust. Until you do, a tool that appeared after the last baseline is treated as drift and its calls are blocked. Run it with no server name to see what is waiting.
usage: mcpgawk approve [-h] [--all] [--list] [server] positional arguments: server the server name as it appears in your config, or its asserted identity options: -h, --help show this help message and exit --all approve every server with pending drift --list show which servers have changes you have not approved, and change nothing
mcpgawk decide
The one screen a human is required for. Opens a LOCAL page showing each server that changed since you trusted it, what changed, and lets you approve or keep blocking. Read-only over your state until you click; approval needs the token printed here, so an agent cannot drive it.
usage: mcpgawk decide [-h] [--port PORT] [--no-open] options: -h, --help show this help message and exit --port PORT local port (default: 7717) --no-open print the URL, do not open a browser
mcpgawk guard
Puts the approved baseline in your agent's loop. A single PreToolUse hook, installed once, checks every MCP tool call — no per-server rewiring and no proxy. The decision is made locally in ~10ms; nothing is uploaded and there is nothing to sign in to.
usage: mcpgawk guard [-h] [--settings PATH] [{status,install,uninstall}]
positional arguments:
{status,install,uninstall}
default: status
options:
-h, --help show this help message and exit
--settings PATH settings file to edit (default: ~/.claude/settings.json)mcpgawk wrong
The false-positive affordance. `mcpgawk wrong <server> <tool>/<kind>` records that YOU judged that finding wrong. It keeps appearing, labelled 'muted by you', because a mistake you silenced must stay reviewable — absence of a finding is never safety, including absence you asked for.
usage: mcpgawk wrong [-h] [--undo] server finding-id
positional arguments:
server the server name as it appears in your config
finding-id the finding as the report prints it: <tool>/<kind>, e.g.
read_note/injection:reader-directed
options:
-h, --help show this help message and exit
--undo withdraw the muteLook closer
Run a server and watch it, or read what happened.
mcpgawk verify
config.json: { "mcpServers": { "local": { "command": "node", "args": ["server.js"], "allowedHosts": ["api.myservice.com"] }, "remote": { "url": "https://mcp.example.com/mcp", "transport": "http", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } } } } Local (stdio) servers run in a no-egress sandbox — all checks apply. Remote (http/sse) servers can't be sandboxed — only output-based checks (tool-poisoning) apply. ${VAR_NAME} in "headers"/"env" values is substituted from the environment at load time — so a config.json committed to a repo never needs to contain a literal secret (export MCP_TOKEN=... and mcpgawk verify resolves it; a config that references an unset variable fails loudly at startup). --isolate: run local servers in an OS-level container sandbox whose ONLY route out is the verifying egress proxy (ADR-0014). Blocks raw-socket/DNS/UDP exfil outright AND still observes every HTTP(S) destination — allowlisted hosts stay reachable, so SSRF-canary / undeclared-egress checks keep their signal. Covers node/python scripts and install-on-launch commands (npx/uvx); the package install runs contained too, observed against an explicit registry allowlist. Requires Docker; degrades to the default proxy sandbox with a warning otherwise. Slower per probe (a container network per call) — the default remains the everyday path. --baseline <file>: first run records a fingerprint of each server's tools; later runs flag DRIFT (added / removed / changed tools) — i.e. a rug-pull. --behaviour-profile <file>: write a gawk.behaviour/1 profile (per-tool observed source/sink) — feed it to `mcpgawk enforce --behaviour-profile` so toxic-flow blocks by BEHAVIOUR, not name. --sarif <file>: write a SARIF 2.1.0 report — GitHub code scanning / most CI security dashboards ingest this natively. A suppressed finding is encoded as a SARIF suppression (shows as "dismissed" on GitHub), not silently dropped from the file. --junit <file>: write a JUnit XML report — renders as a pass/fail test tree in most CI UIs. A suppressed finding becomes a <skipped/> testcase, not a <failure> or nothing. --suppress <file>: exclude REVIEWED findings (by deterministic findingId) from status/exit-code — a legitimate, accepted finding no longer fails CI forever. Never auto-created; use `mcpgawk verify suppress` to add an entry after actually reviewing a finding. Suppressed findings still APPEAR in every output format, marked, never hidden. --webhook <url>: POST the JSON report to <url> when there are findings or drift (alert sink). --audit-log <file>: append ONE JSONL line per reproduction attempt (every attempt, not just ones that produce a finding) — server/tool/check/attempt, whether it completed, the raw response text (truncated to 2000 chars) and egress observed, or the infra failure detail. A "clean" report on its own is a verdict to trust; this is the evidence to check that verdict against. Off by default (raw tool output may contain the target's own data — opt in deliberately). --out <file>: write the JSON report incrementally as each server finishes, not only once at the very end (atomic tmp-file-then-rename, same pattern as never leaving a half-written file). A killed/timed-out run (a slow OAuth-fronted remote, a hung server) leaves the last-known-good snapshot on disk instead of losing every server that already finished cleanly. --json still controls whether the full report also prints to stdout at the end; --out is independent of it. --audit-source: ALSO statically audit each server's SOURCE CODE (AST + semgrep, handled by the Python side before this CLI runs — you won't see these flags again in errors from here). Local script paths are audited in place; npm/pypi launch specs (npx/uvx) are fetched from the public registry — a network call, fetch-only, nothing executed. Remote (url) servers have no local source: reported not-applicable. --source-dir <path>: with --audit-source, skip resolution and audit exactly this directory (single-server configs only). serve: open a local web UI (default http://127.0.0.1:7878) to paste a config and verify in the browser. suppress: record that a specific findingId (from a prior run's output) has been reviewed and accepted — appends to --file, creating it if it doesn't exist yet.
usage: mcpgawk verify <config.json> [--unsafe] [--isolate] [--json] [--html <file>] [--csv <file>]
[--sarif <file>] [--junit <file>] [--behaviour-profile <file>] [--suppress <file>]
[--baseline <file>] [--webhook <url>] [--audit-log <file>] [--out <file>]
[--audit-source] [--source-dir <path>]
mcpgawk verify serve [--port <n>] [--host <addr>] # local web UI
mcpgawk verify suppress <findingId> --file <file> --reason "<why>" [--approved-by "<who>"]mcpgawk panel
One window over the whole machine: which agents are covered, every MCP server and its state, what the runtime guard has actually seen, and anything waiting on you. A control surface, not a viewer: re-scan, verify, sign-in, approve and protect all live here — but only on the tokened URL this command prints. A bare 127.0.0.1:7718 (bookmark, restored tab) renders read-only with no buttons, by design. Drift decisions also live in `mcpgawk decide`.
usage: mcpgawk panel [-h] [--port PORT] [--no-open] options: -h, --help show this help message and exit --port PORT local port (default: 7718) --no-open print the URL, do not open a browser
mcpgawk runs
Your local run history — scans, and (with mcpgawk Platform) verify, enforce and monitor runs, newest first. Read from ~/.mcpgawk/runs.db; nothing is uploaded anywhere. A run that never closed shows as RUNNING, and as INCOMPLETE once its process is gone — it is never reported as success.
usage: mcpgawk runs [-h] [--kind {scan,verify,enforce,monitor,guard}] [--limit LIMIT]
[--json] [--prune]
options:
-h, --help show this help message and exit
--kind {scan,verify,enforce,monitor,guard}
only this kind of run
--limit LIMIT how many to show (default 20)
--json machine-readable output
--prune drop finished runs older than 90 days, then report what is leftmcpgawk demo
A self-contained walkthrough: mcpgawk plants a deliberately-bad MCP server in a temporary sandbox, measures it, you approve it, the server turns hostile, and the guard blocks the tool that appeared afterwards. Nothing touches your real fleet, agents, or state. Offline; a few seconds.
usage: mcpgawk demo [-h] [--sandbox DIR] [--clean] options: -h, --help show this help message and exit --sandbox DIR use this directory for the sandbox instead of a fresh temp one --clean delete the sandbox on exit (default: keep it so you can inspect it)
When something goes wrong
Capture what happened, redacted, in one file you can send.
mcpgawk checkup
Exercises every surface in turn — version, status, scan, verify, the run history and every panel tab — then writes one file with what each step did. A step that fails is kept, not hidden: that is the point. Steps that would launch your local servers ask once and can be declined without stopping the rest. Nothing is uploaded. Stop it at any time with Ctrl-C and the bundle is still written.
usage: mcpgawk checkup [-h] [--output PATH] [--note TEXT] [--yes] [--strict] options: -h, --help show this help message and exit --output PATH write here instead of ./mcpgawk-checkup-<timestamp>.zip --note TEXT what you were trying to do — travels in the bundle --yes, -y do not ask before launching local servers (for a non-interactive run) --strict remove hostnames, package names and command arguments as well
mcpgawk report
Collects everything about this machine into a single redacted zip: version and how mcpgawk was installed, per-agent hook state, the entire run history, the entire call log, every verify run, open drift alerts, and an inventory of both state directories. Nothing is uploaded — the command prints a path and stops. Server responses are removed by field name, home directories become ~, and every URL keeps its parameter names and loses their values. A store that could not be read is listed as 'unavailable', which means nobody looked — never 'nothing there'.
usage: mcpgawk report [-h] [--output PATH] [--strict] [--note TEXT]
options:
-h, --help show this help message and exit
--output PATH write here instead of ./mcpgawk-report-<timestamp>.zip
--strict also remove hostnames, package names and command arguments — for a machine
whose owner will not let internal infrastructure leave it (credentials,
server responses and env values are always removed)
--note TEXT what you were doing when it went wrong — travels in the bundleSet up and account
Installation, licensing and the bits you touch once.
mcpgawk install-node
Download the Node runtime that `verify` uses to run a server in a sandbox. About 26 MB, into mcpgawk's own directory: no admin rights, and nothing on the system is changed.
usage: mcpgawk install-node [-h] [--yes]
options:
-h, --help show this help message and exit
--yes, -y skip the confirmation — required in a non-interactive session, because this
downloads and then RUNS third-party codemcpgawk login
Validates your key against Lemon Squeezy and saves it to ~/.gawk/config.json (mode 0600) so you don't need to export GAWK_LICENSE_KEY yourself. Re-run any time to switch keys.
usage: mcpgawk login <license-key>
mcpgawk logout
mcpgawk logout: no saved key to remove.
mcpgawk skills
Discovers agent skills across every supported host (Claude Code, Codex, Cursor, Copilot, Windsurf, Antigravity, Kiro, Gemini, opencode, Amp) and scans their content locally — nothing is uploaded anywhere. Give paths to scan a specific skill dir, a skills root, or a project instead of the whole machine.
usage: mcpgawk skills [-h] [--json] [--fail-on-findings] [paths ...]
positional arguments:
paths skill dir / skills root / project root (default: discover all hosts)
options:
-h, --help show this help message and exit
--json machine-readable output
--fail-on-findings exit 1 if any finding fires (CI gate) — default reports and exits 0,
because a signal is a signal, not a verdictmcpgawk push
Push a scan receipt (Report v0) to your Finix dashboard fleet. The server appears in the dashboard even though you never scanned it from the portal -- that is the point. mcpgawk push --http https://your-server/mcp scan a live server and push the receipt mcpgawk push --stdio "npx -y @scope/server /tmp" scan a local stdio server and push mcpgawk push --file report.json push a Report v0 your CI already produced Needs a license key: `mcpgawk login <key>` once, or export GAWK_LICENSE_KEY (CI). Endpoint overridable via GAWK_INGEST_URL.
usage: mcpgawk push (--stdio "<cmd>" | --http <url> | --sse <url> | --file <report.json>) [--source cli|ci]