fullcourtdefense-cli 1.7.25 → 1.7.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/mcpGateway.js +52 -6
- package/dist/index.js +232 -232
- package/dist/version.json +1 -1
- package/package.json +1 -1
|
@@ -768,10 +768,23 @@ function buildGatewayCommandArgs(gatewayConfig, downstreamCommand, downstreamArg
|
|
|
768
768
|
'--fail-closed', String(gatewayConfig.failClosed),
|
|
769
769
|
];
|
|
770
770
|
if (!options.omitSavedCredentials) {
|
|
771
|
-
|
|
772
|
-
|
|
771
|
+
// INVARIANT: a shield ID and its shield key must travel together. Writing
|
|
772
|
+
// the shield ID into the config WITHOUT its key lets the runtime pair that
|
|
773
|
+
// ID with a DIFFERENT shield's key resolved from ~/.fullcourtdefense.yml.
|
|
774
|
+
// The backend then returns 401 (SHIELD_KEY_REQUIRED) and, under
|
|
775
|
+
// --fail-closed, EVERY tool call is blocked — even a read-only lookup.
|
|
776
|
+
// This was the Claude Desktop "stale shield" bug: the config pinned an old
|
|
777
|
+
// shield ID while the machine had been re-enrolled to a different shield.
|
|
778
|
+
const persistKey = !!gatewayConfig.shieldKey && options.includeShieldKey !== false;
|
|
779
|
+
if (persistKey) {
|
|
780
|
+
// Self-contained config: ID + matching key baked in as a pair.
|
|
781
|
+
commandArgs.push('--shield-id', gatewayConfig.shieldId);
|
|
773
782
|
commandArgs.push('--shield-key', gatewayConfig.shieldKey);
|
|
774
783
|
}
|
|
784
|
+
// When the key is intentionally kept out of the config
|
|
785
|
+
// (includeShieldKey === false), we also OMIT the shield ID so the runtime
|
|
786
|
+
// resolves BOTH as a matched pair from ~/.fullcourtdefense.yml — the same
|
|
787
|
+
// proven path the Cursor hooks use. Never write the ID alone.
|
|
775
788
|
if (gatewayConfig.apiUrl)
|
|
776
789
|
commandArgs.push('--api-url', gatewayConfig.apiUrl);
|
|
777
790
|
}
|
|
@@ -1055,7 +1068,7 @@ const CLIENT_KEY_TO_AGENT = {
|
|
|
1055
1068
|
windsurf: 'windsurf',
|
|
1056
1069
|
vscode: 'vscode',
|
|
1057
1070
|
};
|
|
1058
|
-
function newWrapStats() { return { wrapped: [], skippedManaged: [], skippedRemote: [] }; }
|
|
1071
|
+
function newWrapStats() { return { wrapped: [], healed: [], skippedManaged: [], skippedRemote: [] }; }
|
|
1059
1072
|
/** True when an MCP server entry already runs through the AgentGuard gateway. */
|
|
1060
1073
|
function isGatewayWrappedEntry(entry) {
|
|
1061
1074
|
if (!entry || typeof entry !== 'object')
|
|
@@ -1063,6 +1076,20 @@ function isGatewayWrappedEntry(entry) {
|
|
|
1063
1076
|
const args = Array.isArray(entry.args) ? entry.args.map(String) : [];
|
|
1064
1077
|
return args.includes('mcp-gateway');
|
|
1065
1078
|
}
|
|
1079
|
+
/**
|
|
1080
|
+
* A wrapped entry is STALE/broken when it pins a `--shield-id` but carries no
|
|
1081
|
+
* matching `--shield-key`. At runtime the gateway then pairs that shield ID with
|
|
1082
|
+
* whatever key ~/.fullcourtdefense.yml holds — if the machine was re-enrolled to
|
|
1083
|
+
* a different shield, the pair mismatches, the backend returns 401, and
|
|
1084
|
+
* --fail-closed blocks EVERY tool call. Entries written by the fixed installer
|
|
1085
|
+
* carry either BOTH (self-contained) or NEITHER (resolved as a matched pair from
|
|
1086
|
+
* the yml), so `id without key` uniquely identifies the buggy old wrapping that
|
|
1087
|
+
* must be re-wrapped in place.
|
|
1088
|
+
*/
|
|
1089
|
+
function wrappedEntryNeedsHeal(entry) {
|
|
1090
|
+
const args = Array.isArray(entry?.args) ? entry.args.map(String) : [];
|
|
1091
|
+
return args.includes('--shield-id') && !args.includes('--shield-key');
|
|
1092
|
+
}
|
|
1066
1093
|
/** Recover the original downstream command+args from a wrapped entry's args. */
|
|
1067
1094
|
function extractWrappedDownstream(entry) {
|
|
1068
1095
|
const args = Array.isArray(entry?.args) ? entry.args.map(String) : [];
|
|
@@ -1135,6 +1162,21 @@ function wrapJsonConfigFile(file, gatewayConfig, agentClient, dryRun) {
|
|
|
1135
1162
|
if (!entry || typeof entry !== 'object')
|
|
1136
1163
|
continue;
|
|
1137
1164
|
if (name === MANAGED_SERVER_NAME || isGatewayWrappedEntry(entry)) {
|
|
1165
|
+
// Already wrapped — but re-heal in place if it carries the stale
|
|
1166
|
+
// shield-id-without-key that caused the fail-closed 401 block. Recover
|
|
1167
|
+
// the original downstream server from the existing wrapper args and
|
|
1168
|
+
// rewrap with the fixed matched-pair credential handling.
|
|
1169
|
+
if (isGatewayWrappedEntry(entry) && wrappedEntryNeedsHeal(entry)) {
|
|
1170
|
+
const downstream = extractWrappedDownstream(entry);
|
|
1171
|
+
if (downstream) {
|
|
1172
|
+
const perServer = { ...gatewayConfig, agentClient, agentName: perServerAgentName(gatewayConfig.developerName, agentClient, name) };
|
|
1173
|
+
entry.command = nodeExe;
|
|
1174
|
+
entry.args = buildGatewayCommandArgs(perServer, downstream.command, downstream.args, INSTALL_GATEWAY_ARGS);
|
|
1175
|
+
stats.healed.push(name);
|
|
1176
|
+
changed = true;
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1138
1180
|
stats.skippedManaged.push(name);
|
|
1139
1181
|
continue;
|
|
1140
1182
|
}
|
|
@@ -1370,6 +1412,7 @@ async function protectAllCommand(args, config) {
|
|
|
1370
1412
|
}
|
|
1371
1413
|
console.log(`\x1b[2mAuto-searching every known MCP client on this machine — ${files.length} config file(s) found.\x1b[0m\n`);
|
|
1372
1414
|
let totalWrapped = 0;
|
|
1415
|
+
let totalHealed = 0;
|
|
1373
1416
|
let totalManaged = 0;
|
|
1374
1417
|
let totalRemote = 0;
|
|
1375
1418
|
let totalEmpty = 0;
|
|
@@ -1386,12 +1429,15 @@ async function protectAllCommand(args, config) {
|
|
|
1386
1429
|
console.log(' \x1b[33m• could not parse — left unchanged\x1b[0m\n');
|
|
1387
1430
|
continue;
|
|
1388
1431
|
}
|
|
1389
|
-
const found = stats.wrapped.length + stats.skippedManaged.length + stats.skippedRemote.length;
|
|
1432
|
+
const found = stats.wrapped.length + stats.healed.length + stats.skippedManaged.length + stats.skippedRemote.length;
|
|
1390
1433
|
totalWrapped += stats.wrapped.length;
|
|
1434
|
+
totalHealed += stats.healed.length;
|
|
1391
1435
|
totalManaged += stats.skippedManaged.length;
|
|
1392
1436
|
totalRemote += stats.skippedRemote.length;
|
|
1393
1437
|
if (stats.wrapped.length)
|
|
1394
1438
|
console.log(` \x1b[32m✓ ${dryRun ? 'would update' : 'updated'} → now protected:\x1b[0m ${stats.wrapped.join(', ')}`);
|
|
1439
|
+
if (stats.healed.length)
|
|
1440
|
+
console.log(` \x1b[32m✓ ${dryRun ? 'would repair' : 'repaired'} stale shield credentials:\x1b[0m ${stats.healed.join(', ')}`);
|
|
1395
1441
|
if (stats.skippedManaged.length)
|
|
1396
1442
|
console.log(` \x1b[2m• already protected (unchanged):\x1b[0m ${stats.skippedManaged.join(', ')}`);
|
|
1397
1443
|
if (stats.skippedRemote.length)
|
|
@@ -1409,9 +1455,9 @@ async function protectAllCommand(args, config) {
|
|
|
1409
1455
|
console.log(`\x1b[2mNot configured (no config file found): ${notConfigured.map(c => CLIENT_LABELS[c]).join(', ')}\x1b[0m\n`);
|
|
1410
1456
|
}
|
|
1411
1457
|
console.log('\x1b[1mSummary\x1b[0m');
|
|
1412
|
-
console.log(` ${dryRun ? 'would update' : 'updated'}: ${totalWrapped} already protected: ${totalManaged} no servers: ${totalEmpty} skipped remote: ${totalRemote}`);
|
|
1458
|
+
console.log(` ${dryRun ? 'would update' : 'updated'}: ${totalWrapped} ${dryRun ? 'would repair' : 'repaired'}: ${totalHealed} already protected: ${totalManaged} no servers: ${totalEmpty} skipped remote: ${totalRemote}`);
|
|
1413
1459
|
console.log(` Each protected server enforces your org Action Policies (allow / block / wait-for-human-approval) on its tool calls.`);
|
|
1414
|
-
if (!dryRun && totalWrapped > 0) {
|
|
1460
|
+
if (!dryRun && (totalWrapped > 0 || totalHealed > 0)) {
|
|
1415
1461
|
console.log(' Backups saved next to each edited file (*.fcd-backup-*).');
|
|
1416
1462
|
(0, restartNotice_1.printRestartNotice)(allowedClientKeys ? [...allowedClientKeys].join(', ') : undefined);
|
|
1417
1463
|
}
|
package/dist/index.js
CHANGED
|
@@ -104,238 +104,238 @@ function parseArgs(argv) {
|
|
|
104
104
|
return { command, flags };
|
|
105
105
|
}
|
|
106
106
|
function printHelp() {
|
|
107
|
-
console.log(`
|
|
108
|
-
\x1b[1m\x1b[36mFullCourtDefense CLI\x1b[0m v${VERSION}
|
|
109
|
-
Security scanning for AI agents from your terminal.
|
|
110
|
-
|
|
111
|
-
\x1b[1mUsage:\x1b[0m
|
|
112
|
-
fullcourtdefense <command> [options]
|
|
113
|
-
|
|
114
|
-
\x1b[1mCommands:\x1b[0m
|
|
115
|
-
help Show this onboarding guide and command reference.
|
|
116
|
-
doctor First step. Checks outbound HTTPS access to FullCourtDefense.
|
|
117
|
-
login Enrolls this machine with a fleet enrollment token and saves
|
|
118
|
-
per-machine Shield credentials to ~/.fullcourtdefense.yml.
|
|
119
|
-
configure Legacy/manual setup: saves org API key, Organization ID,
|
|
120
|
-
Shield ID, and Shield key to ~/.fullcourtdefense.yml.
|
|
121
|
-
setup Same as configure — manual fallback when not using fleet login.
|
|
122
|
-
install-all One-click: protect existing MCP servers in every AI client and
|
|
123
|
-
install available runtime hooks for built-in actions. No folder path
|
|
124
|
-
or --mcp-command needed. Use --hooks false to skip runtime hooks.
|
|
125
|
-
install Alias for install-all.
|
|
126
|
-
scan Runs the scan. Use --local for inside-organization scans.
|
|
127
|
-
discover Finds MCP servers, local secrets, agent rules/skills, and machine
|
|
128
|
-
blast radius on this laptop. Use --surface all --upload for AI Fleet.
|
|
129
|
-
Use --schedule logon to upload inventory/posture at machine login.
|
|
130
|
-
agent-ci CI/CD gate for agents and tools only. Fails builds on risky MCP,
|
|
131
|
-
agent instruction, gateway, policy, or secret drift. Not a bot scan.
|
|
132
|
-
install-cursor-hook
|
|
133
|
-
Installs a Cursor hook so EVERY agent action on this machine is
|
|
134
|
-
checked against your org's Action Policies — in any repo/folder.
|
|
135
|
-
Prompts are scanned by your Shield; shell/MCP/file/read actions
|
|
136
|
-
are allowed, blocked, or paused for human approval per policy.
|
|
137
|
-
uninstall-cursor-hook
|
|
138
|
-
Removes the FullCourtDefense Cursor hook entries.
|
|
139
|
-
install-claude-hook
|
|
140
|
-
Installs Claude-format hooks in ~/.claude/settings.json — ONE file
|
|
141
|
-
enforces Action Policies + Local Safety rules in Claude Code,
|
|
142
|
-
VS Code Copilot agent mode, and GitHub Copilot CLI.
|
|
143
|
-
uninstall-claude-hook
|
|
144
|
-
Removes the FullCourtDefense Claude-format hook entries.
|
|
145
|
-
protect-all Auto-detect EVERY MCP server already configured in EVERY client
|
|
146
|
-
(Cursor, Claude Code/Desktop, Codex, Gemini, Windsurf, VS Code)
|
|
147
|
-
and wrap each through the Shield proxy — no --mcp-command needed.
|
|
148
|
-
Enforces your org Action Policies on every tool. --dry-run to preview.
|
|
149
|
-
Per-tool: --clients cursor (or claude-code, claude-desktop, codex,
|
|
150
|
-
gemini-cli, windsurf, vscode; comma-separated). Default: all tools.
|
|
151
|
-
unprotect-all
|
|
152
|
-
Reverse protect-all: restore every server to its original command.
|
|
153
|
-
Also supports --clients to target one tool, and --dry-run.
|
|
154
|
-
auto-protect
|
|
155
|
-
Self-healing: schedule protect-all to re-run automatically so any
|
|
156
|
-
server that loses the proxy is re-wrapped. --interval-minutes 60
|
|
157
|
-
(default) or --on-logon true. --uninstall true / --status true.
|
|
158
|
-
install-mcp-gateway
|
|
159
|
-
Install MCP gateway into selected clients (--clients all for every tool).
|
|
160
|
-
install-cursor-mcp-gateway
|
|
161
|
-
Cursor only — adds gateway to mcp.json.
|
|
162
|
-
install-claude-code-mcp-gateway
|
|
163
|
-
Claude Code only — uses claude mcp add or .mcp.json.
|
|
164
|
-
install-claude-desktop-mcp-gateway
|
|
165
|
-
Claude Desktop only.
|
|
166
|
-
install-codex-mcp-gateway
|
|
167
|
-
Codex only — writes ~/.codex/config.toml.
|
|
168
|
-
install-gemini-mcp-gateway
|
|
169
|
-
Gemini CLI only — writes settings.json mcpServers.
|
|
170
|
-
install-windsurf-mcp-gateway
|
|
171
|
-
Windsurf only.
|
|
172
|
-
install-vscode-mcp-gateway
|
|
173
|
-
VS Code only — .vscode/mcp.json or user settings.
|
|
174
|
-
mcp-gateway
|
|
175
|
-
Runs a local MCP gateway that checks AgentGuard runtime/action
|
|
176
|
-
policies before forwarding tool calls to a real MCP server.
|
|
177
|
-
hook Internal: invoked by Cursor per agent event (reads stdin JSON,
|
|
178
|
-
returns an allow/deny verdict). Not run by hand.
|
|
179
|
-
credits Shows hosted scan credits for CI/CD API-key scans.
|
|
180
|
-
init Creates a starter .fullcourtdefense.yml config file.
|
|
181
|
-
|
|
182
|
-
\x1b[1mNew User Process:\x1b[0m
|
|
183
|
-
1. In the web app, an org admin creates a fleet enrollment token:
|
|
184
|
-
AI Fleet → Settings → Fleet enrollment token.
|
|
185
|
-
|
|
186
|
-
2. Check outbound connectivity from the customer machine:
|
|
187
|
-
fullcourtdefense doctor
|
|
188
|
-
This confirms the machine can reach https://api.fullcourtdefense.ai over HTTPS.
|
|
189
|
-
|
|
190
|
-
3. Enroll this developer machine (one time):
|
|
191
|
-
fullcourtdefense login --token <fleet-enrollment-token>
|
|
192
|
-
Or set FCD_ENROLL_TOKEN and run: fullcourtdefense login
|
|
193
|
-
Saves per-machine Shield credentials to ~/.fullcourtdefense.yml —
|
|
194
|
-
install, discover --upload, scan, gateway, and hooks use it automatically.
|
|
195
|
-
|
|
196
|
-
4. One-click protect every AI client on this machine with Action Policies:
|
|
197
|
-
fullcourtdefense install-all
|
|
198
|
-
Verify installs:
|
|
199
|
-
fullcourtdefense protect-all --dry-run true
|
|
200
|
-
Or install one client: fullcourtdefense install-cursor-mcp-gateway ...
|
|
201
|
-
|
|
202
|
-
5. Run a guided local scan:
|
|
203
|
-
fullcourtdefense scan --local
|
|
204
|
-
The CLI asks whether to scan endpoint, mcp, or rag.
|
|
205
|
-
To open the localhost web scan UI first:
|
|
206
|
-
fullcourtdefense scan --local --open-ui
|
|
207
|
-
|
|
208
|
-
6. Review results:
|
|
209
|
-
Use --format summary for CI, --format table for terminal view,
|
|
210
|
-
--format report for evidence, --format full-report for every row,
|
|
211
|
-
or --format json for raw output.
|
|
212
|
-
With a Shield key configured, reports are saved to the web Reports page
|
|
213
|
-
and the browser opens to the saved report. Use --no-open to suppress.
|
|
214
|
-
|
|
215
|
-
\x1b[1mLocal Destinations:\x1b[0m
|
|
216
|
-
endpoint Internal HTTP URL, for example http://agent.local/chat.
|
|
217
|
-
The CLI sends attack prompts to this endpoint and scans responses.
|
|
218
|
-
|
|
219
|
-
mcp Either stdio command + args, or an already-running HTTP/SSE MCP URL.
|
|
220
|
-
Stdio example: node ./mcp-server.js
|
|
221
|
-
HTTP/HTTPS examples: http://mcp.internal/mcp or https://internal.company.com/mcp
|
|
222
|
-
Legacy SSE example: https://internal.company.com/sse
|
|
223
|
-
Secured HTTP MCP supports bearer, basic, and API-key auth.
|
|
224
|
-
|
|
225
|
-
rag File/directory path or live RAG HTTP endpoint.
|
|
226
|
-
Use --rag-path for local documents, or --rag-url for a RAG service.
|
|
227
|
-
|
|
228
|
-
\x1b[1mRecommended Commands:\x1b[0m
|
|
229
|
-
fullcourtdefense doctor
|
|
230
|
-
fullcourtdefense configure
|
|
231
|
-
fullcourtdefense agent-ci --fail-on high --require-gateway --format summary
|
|
232
|
-
fullcourtdefense agent-ci --fail-on high --format sarif --upload
|
|
233
|
-
fullcourtdefense scan --local
|
|
234
|
-
fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
235
|
-
fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-auth-type bearer --mcp-token TOKEN --mcp-tool all --mode full --format report
|
|
236
|
-
fullcourtdefense scan --local --type rag --rag-path ./docs --format report
|
|
237
|
-
fullcourtdefense scan --local --type rag --rag-url http://rag.internal/chat --method POST --request-format custom --input-field message --output-field answer --mode full --format report
|
|
238
|
-
fullcourtdefense scan --local --type endpoint --endpoint http://agent.local/chat --method POST --mode full --format report
|
|
239
|
-
|
|
240
|
-
\x1b[1mScan Options:\x1b[0m
|
|
241
|
-
--local Run scan from this machine, inside your network
|
|
242
|
-
--open-ui Open localhost browser scan UI with all options
|
|
243
|
-
--type <type> Local scan type: endpoint, mcp, rag
|
|
244
|
-
--api-key <key> API key (or set FULLCOURTDEFENSE_API_KEY env var)
|
|
245
|
-
--api-url <url> API base URL (default: https://api.fullcourtdefense.ai)
|
|
246
|
-
--endpoint <url> Agent API endpoint to scan
|
|
247
|
-
--mcp-url <url> Already-running HTTP MCP server URL
|
|
248
|
-
--mcp-transport <t> MCP transport: stdio, http, or sse
|
|
249
|
-
--mcp-command <cmd> MCP server command, for example node or npx.cmd
|
|
250
|
-
--mcp-args <args> MCP server args/path, for example ./server.js
|
|
251
|
-
--mcp-tool <tool> MCP tool to test, or all
|
|
252
|
-
--server-name <name> MCP gateway server name for client installers
|
|
253
|
-
--clients <list> Gateway clients: all, auto, cursor, claude-code,
|
|
254
|
-
claude-desktop, codex, gemini-cli, windsurf, vscode
|
|
255
|
-
--developer-name <name> Runtime identity for user-scoped policies (auto-detected if omitted)
|
|
256
|
-
--agent-name <name> Runtime agent name (auto-generated from identity + client if omitted)
|
|
257
|
-
--scope <scope> Claude Code MCP scope: local, project, or user
|
|
258
|
-
--claude-code-scope <s> Claude Code scope for install-mcp-gateway
|
|
259
|
-
--cursor-project <bool> Cursor project config for install-mcp-gateway
|
|
260
|
-
--config-path <path> Claude Desktop config override path
|
|
261
|
-
--mcp-auth-type <type> HTTP MCP auth: none, bearer, basic, api-key
|
|
262
|
-
--mcp-token <token> HTTP MCP bearer token
|
|
263
|
-
--mcp-username <user> HTTP MCP basic username
|
|
264
|
-
--mcp-password <pass> HTTP MCP basic password
|
|
265
|
-
--mcp-api-key-header <h> HTTP MCP API-key header name
|
|
266
|
-
--mcp-api-key <key> HTTP MCP API key value
|
|
267
|
-
--rag-path <path> RAG file or directory to scan
|
|
268
|
-
--rag-url <url> Live RAG HTTP endpoint to scan
|
|
269
|
-
--shield-id <id> Shield ID for local outbound Shield verdicts
|
|
270
|
-
--shield-key <key> Optional Shield key for locked Shields
|
|
271
|
-
--fail-on <severity> agent-ci fail threshold: critical, high, medium, low
|
|
272
|
-
--require-gateway agent-ci requires risky MCP servers to use FCD gateway
|
|
273
|
-
--require-approval-for agent-ci risky controls list, e.g. payment,delete,shell,secrets
|
|
274
|
-
--require-upload agent-ci fails if evidence cannot upload to AgentGuard UI
|
|
275
|
-
--changed-only agent-ci limits findings to changed files
|
|
276
|
-
--changed-files <path> file or comma/newline list of changed files for agent-ci
|
|
277
|
-
--method <GET|POST> Local endpoint method
|
|
278
|
-
--request-format <fmt> Local endpoint request format: custom or openai
|
|
279
|
-
--auth-type <type> none, bearer, basic, api-key
|
|
280
|
-
--description <text> Agent description
|
|
281
|
-
--system-prompt <text> System prompt (text or path to file)
|
|
282
|
-
--mode <sync|async> Hosted mode, or local mode: quick, full, targeted, deep
|
|
283
|
-
--categories <list> Comma-separated attack categories
|
|
284
|
-
--attack-count <n> Number of attacks to run
|
|
285
|
-
--surface <list> Discover surfaces: mcp, secrets, agent-files, posture, all
|
|
286
|
-
--fail-threshold <n> Exit code 1 if score below n (default: 0)
|
|
287
|
-
--format <fmt> Output: table, json, summary, report, full-report (default: table)
|
|
288
|
-
--open Open browser scan UI and saved local scan report
|
|
289
|
-
--open-ui Open only the browser scan UI before local execution
|
|
290
|
-
--no-open Do not open the browser during/after local scans
|
|
291
|
-
--webhook-format <fmt> Hosted webhook format, or legacy local request format
|
|
292
|
-
--config <path> Path to .fullcourtdefense.yml config file
|
|
293
|
-
|
|
294
|
-
\x1b[1mExamples:\x1b[0m
|
|
295
|
-
$ fullcourtdefense scan --endpoint https://my-bot.com/chat --description "Support bot"
|
|
296
|
-
$ fullcourtdefense help
|
|
297
|
-
$ fullcourtdefense scan --local
|
|
298
|
-
$ fullcourtdefense scan --local --open-ui
|
|
299
|
-
$ fullcourtdefense scan --local --type endpoint --mode full --endpoint http://internal-agent/chat
|
|
300
|
-
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full
|
|
301
|
-
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp
|
|
302
|
-
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-tool all --mode full
|
|
303
|
-
$ fullcourtdefense scan --local --type mcp --mcp-transport sse --mcp-url https://internal.company.com/sse --mcp-tool all --mode full
|
|
304
|
-
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
305
|
-
$ fullcourtdefense discover
|
|
306
|
-
$ fullcourtdefense discover --surface mcp
|
|
307
|
-
$ fullcourtdefense discover --surface all --upload
|
|
308
|
-
$ fullcourtdefense discover --surface secrets
|
|
309
|
-
$ fullcourtdefense discover --surface agent-files
|
|
310
|
-
$ fullcourtdefense discover --deep --upload --silent --user-email you@company.com
|
|
311
|
-
$ fullcourtdefense discover --type mcp --json
|
|
312
|
-
$ fullcourtdefense install-cursor-hook
|
|
313
|
-
$ fullcourtdefense install-cursor-hook --shadow true # monitor only
|
|
314
|
-
$ fullcourtdefense install-cursor-hook --events prompt,shell,mcp,file
|
|
315
|
-
$ fullcourtdefense install-cursor-hook --project true # this repo only
|
|
316
|
-
$ fullcourtdefense uninstall-cursor-hook
|
|
317
|
-
$ fullcourtdefense install-claude-hook # Claude Code + VS Code + Copilot CLI
|
|
318
|
-
$ fullcourtdefense install-claude-hook --events tools,prompt # also scan prompts
|
|
319
|
-
$ fullcourtdefense uninstall-claude-hook
|
|
320
|
-
$ fullcourtdefense install-mcp-gateway --clients auto --mcp-command npm --mcp-args "run mcp"
|
|
321
|
-
$ fullcourtdefense install-mcp-gateway --clients all --mcp-command npm --mcp-args "run mcp" --upload
|
|
322
|
-
$ fullcourtdefense install-cursor-mcp-gateway --project true --mcp-command npm --mcp-args "run mcp"
|
|
323
|
-
$ fullcourtdefense install-claude-code-mcp-gateway --scope local --mcp-command npm --mcp-args "run mcp"
|
|
324
|
-
$ fullcourtdefense install-claude-code-mcp-gateway --scope project --mcp-command npm --mcp-args "run mcp"
|
|
325
|
-
$ fullcourtdefense install-claude-desktop-mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
326
|
-
$ fullcourtdefense mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
327
|
-
$ fullcourtdefense login --token <fleet-enrollment-token>
|
|
328
|
-
$ fullcourtdefense install-all
|
|
329
|
-
$ fullcourtdefense install-all --auto-protect true --upload
|
|
330
|
-
$ fullcourtdefense discover --surface all --upload --schedule logon
|
|
331
|
-
$ fullcourtdefense install-mcp-gateway --clients cursor,codex --mcp-command npm --mcp-args "run mcp"
|
|
332
|
-
$ fullcourtdefense install-codex-mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
333
|
-
$ fullcourtdefense scan --system-prompt ./prompts/system.md --fail-threshold 80
|
|
334
|
-
$ fullcourtdefense scan --config .fullcourtdefense.yml --format json
|
|
335
|
-
$ fullcourtdefense credits
|
|
336
|
-
$ fullcourtdefense init
|
|
337
|
-
|
|
338
|
-
\x1b[2mDocs: https://fullcourtdefense.ai/docs/cli\x1b[0m
|
|
107
|
+
console.log(`
|
|
108
|
+
\x1b[1m\x1b[36mFullCourtDefense CLI\x1b[0m v${VERSION}
|
|
109
|
+
Security scanning for AI agents from your terminal.
|
|
110
|
+
|
|
111
|
+
\x1b[1mUsage:\x1b[0m
|
|
112
|
+
fullcourtdefense <command> [options]
|
|
113
|
+
|
|
114
|
+
\x1b[1mCommands:\x1b[0m
|
|
115
|
+
help Show this onboarding guide and command reference.
|
|
116
|
+
doctor First step. Checks outbound HTTPS access to FullCourtDefense.
|
|
117
|
+
login Enrolls this machine with a fleet enrollment token and saves
|
|
118
|
+
per-machine Shield credentials to ~/.fullcourtdefense.yml.
|
|
119
|
+
configure Legacy/manual setup: saves org API key, Organization ID,
|
|
120
|
+
Shield ID, and Shield key to ~/.fullcourtdefense.yml.
|
|
121
|
+
setup Same as configure — manual fallback when not using fleet login.
|
|
122
|
+
install-all One-click: protect existing MCP servers in every AI client and
|
|
123
|
+
install available runtime hooks for built-in actions. No folder path
|
|
124
|
+
or --mcp-command needed. Use --hooks false to skip runtime hooks.
|
|
125
|
+
install Alias for install-all.
|
|
126
|
+
scan Runs the scan. Use --local for inside-organization scans.
|
|
127
|
+
discover Finds MCP servers, local secrets, agent rules/skills, and machine
|
|
128
|
+
blast radius on this laptop. Use --surface all --upload for AI Fleet.
|
|
129
|
+
Use --schedule logon to upload inventory/posture at machine login.
|
|
130
|
+
agent-ci CI/CD gate for agents and tools only. Fails builds on risky MCP,
|
|
131
|
+
agent instruction, gateway, policy, or secret drift. Not a bot scan.
|
|
132
|
+
install-cursor-hook
|
|
133
|
+
Installs a Cursor hook so EVERY agent action on this machine is
|
|
134
|
+
checked against your org's Action Policies — in any repo/folder.
|
|
135
|
+
Prompts are scanned by your Shield; shell/MCP/file/read actions
|
|
136
|
+
are allowed, blocked, or paused for human approval per policy.
|
|
137
|
+
uninstall-cursor-hook
|
|
138
|
+
Removes the FullCourtDefense Cursor hook entries.
|
|
139
|
+
install-claude-hook
|
|
140
|
+
Installs Claude-format hooks in ~/.claude/settings.json — ONE file
|
|
141
|
+
enforces Action Policies + Local Safety rules in Claude Code,
|
|
142
|
+
VS Code Copilot agent mode, and GitHub Copilot CLI.
|
|
143
|
+
uninstall-claude-hook
|
|
144
|
+
Removes the FullCourtDefense Claude-format hook entries.
|
|
145
|
+
protect-all Auto-detect EVERY MCP server already configured in EVERY client
|
|
146
|
+
(Cursor, Claude Code/Desktop, Codex, Gemini, Windsurf, VS Code)
|
|
147
|
+
and wrap each through the Shield proxy — no --mcp-command needed.
|
|
148
|
+
Enforces your org Action Policies on every tool. --dry-run to preview.
|
|
149
|
+
Per-tool: --clients cursor (or claude-code, claude-desktop, codex,
|
|
150
|
+
gemini-cli, windsurf, vscode; comma-separated). Default: all tools.
|
|
151
|
+
unprotect-all
|
|
152
|
+
Reverse protect-all: restore every server to its original command.
|
|
153
|
+
Also supports --clients to target one tool, and --dry-run.
|
|
154
|
+
auto-protect
|
|
155
|
+
Self-healing: schedule protect-all to re-run automatically so any
|
|
156
|
+
server that loses the proxy is re-wrapped. --interval-minutes 60
|
|
157
|
+
(default) or --on-logon true. --uninstall true / --status true.
|
|
158
|
+
install-mcp-gateway
|
|
159
|
+
Install MCP gateway into selected clients (--clients all for every tool).
|
|
160
|
+
install-cursor-mcp-gateway
|
|
161
|
+
Cursor only — adds gateway to mcp.json.
|
|
162
|
+
install-claude-code-mcp-gateway
|
|
163
|
+
Claude Code only — uses claude mcp add or .mcp.json.
|
|
164
|
+
install-claude-desktop-mcp-gateway
|
|
165
|
+
Claude Desktop only.
|
|
166
|
+
install-codex-mcp-gateway
|
|
167
|
+
Codex only — writes ~/.codex/config.toml.
|
|
168
|
+
install-gemini-mcp-gateway
|
|
169
|
+
Gemini CLI only — writes settings.json mcpServers.
|
|
170
|
+
install-windsurf-mcp-gateway
|
|
171
|
+
Windsurf only.
|
|
172
|
+
install-vscode-mcp-gateway
|
|
173
|
+
VS Code only — .vscode/mcp.json or user settings.
|
|
174
|
+
mcp-gateway
|
|
175
|
+
Runs a local MCP gateway that checks AgentGuard runtime/action
|
|
176
|
+
policies before forwarding tool calls to a real MCP server.
|
|
177
|
+
hook Internal: invoked by Cursor per agent event (reads stdin JSON,
|
|
178
|
+
returns an allow/deny verdict). Not run by hand.
|
|
179
|
+
credits Shows hosted scan credits for CI/CD API-key scans.
|
|
180
|
+
init Creates a starter .fullcourtdefense.yml config file.
|
|
181
|
+
|
|
182
|
+
\x1b[1mNew User Process:\x1b[0m
|
|
183
|
+
1. In the web app, an org admin creates a fleet enrollment token:
|
|
184
|
+
AI Fleet → Settings → Fleet enrollment token.
|
|
185
|
+
|
|
186
|
+
2. Check outbound connectivity from the customer machine:
|
|
187
|
+
fullcourtdefense doctor
|
|
188
|
+
This confirms the machine can reach https://api.fullcourtdefense.ai over HTTPS.
|
|
189
|
+
|
|
190
|
+
3. Enroll this developer machine (one time):
|
|
191
|
+
fullcourtdefense login --token <fleet-enrollment-token>
|
|
192
|
+
Or set FCD_ENROLL_TOKEN and run: fullcourtdefense login
|
|
193
|
+
Saves per-machine Shield credentials to ~/.fullcourtdefense.yml —
|
|
194
|
+
install, discover --upload, scan, gateway, and hooks use it automatically.
|
|
195
|
+
|
|
196
|
+
4. One-click protect every AI client on this machine with Action Policies:
|
|
197
|
+
fullcourtdefense install-all
|
|
198
|
+
Verify installs:
|
|
199
|
+
fullcourtdefense protect-all --dry-run true
|
|
200
|
+
Or install one client: fullcourtdefense install-cursor-mcp-gateway ...
|
|
201
|
+
|
|
202
|
+
5. Run a guided local scan:
|
|
203
|
+
fullcourtdefense scan --local
|
|
204
|
+
The CLI asks whether to scan endpoint, mcp, or rag.
|
|
205
|
+
To open the localhost web scan UI first:
|
|
206
|
+
fullcourtdefense scan --local --open-ui
|
|
207
|
+
|
|
208
|
+
6. Review results:
|
|
209
|
+
Use --format summary for CI, --format table for terminal view,
|
|
210
|
+
--format report for evidence, --format full-report for every row,
|
|
211
|
+
or --format json for raw output.
|
|
212
|
+
With a Shield key configured, reports are saved to the web Reports page
|
|
213
|
+
and the browser opens to the saved report. Use --no-open to suppress.
|
|
214
|
+
|
|
215
|
+
\x1b[1mLocal Destinations:\x1b[0m
|
|
216
|
+
endpoint Internal HTTP URL, for example http://agent.local/chat.
|
|
217
|
+
The CLI sends attack prompts to this endpoint and scans responses.
|
|
218
|
+
|
|
219
|
+
mcp Either stdio command + args, or an already-running HTTP/SSE MCP URL.
|
|
220
|
+
Stdio example: node ./mcp-server.js
|
|
221
|
+
HTTP/HTTPS examples: http://mcp.internal/mcp or https://internal.company.com/mcp
|
|
222
|
+
Legacy SSE example: https://internal.company.com/sse
|
|
223
|
+
Secured HTTP MCP supports bearer, basic, and API-key auth.
|
|
224
|
+
|
|
225
|
+
rag File/directory path or live RAG HTTP endpoint.
|
|
226
|
+
Use --rag-path for local documents, or --rag-url for a RAG service.
|
|
227
|
+
|
|
228
|
+
\x1b[1mRecommended Commands:\x1b[0m
|
|
229
|
+
fullcourtdefense doctor
|
|
230
|
+
fullcourtdefense configure
|
|
231
|
+
fullcourtdefense agent-ci --fail-on high --require-gateway --format summary
|
|
232
|
+
fullcourtdefense agent-ci --fail-on high --format sarif --upload
|
|
233
|
+
fullcourtdefense scan --local
|
|
234
|
+
fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
235
|
+
fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-auth-type bearer --mcp-token TOKEN --mcp-tool all --mode full --format report
|
|
236
|
+
fullcourtdefense scan --local --type rag --rag-path ./docs --format report
|
|
237
|
+
fullcourtdefense scan --local --type rag --rag-url http://rag.internal/chat --method POST --request-format custom --input-field message --output-field answer --mode full --format report
|
|
238
|
+
fullcourtdefense scan --local --type endpoint --endpoint http://agent.local/chat --method POST --mode full --format report
|
|
239
|
+
|
|
240
|
+
\x1b[1mScan Options:\x1b[0m
|
|
241
|
+
--local Run scan from this machine, inside your network
|
|
242
|
+
--open-ui Open localhost browser scan UI with all options
|
|
243
|
+
--type <type> Local scan type: endpoint, mcp, rag
|
|
244
|
+
--api-key <key> API key (or set FULLCOURTDEFENSE_API_KEY env var)
|
|
245
|
+
--api-url <url> API base URL (default: https://api.fullcourtdefense.ai)
|
|
246
|
+
--endpoint <url> Agent API endpoint to scan
|
|
247
|
+
--mcp-url <url> Already-running HTTP MCP server URL
|
|
248
|
+
--mcp-transport <t> MCP transport: stdio, http, or sse
|
|
249
|
+
--mcp-command <cmd> MCP server command, for example node or npx.cmd
|
|
250
|
+
--mcp-args <args> MCP server args/path, for example ./server.js
|
|
251
|
+
--mcp-tool <tool> MCP tool to test, or all
|
|
252
|
+
--server-name <name> MCP gateway server name for client installers
|
|
253
|
+
--clients <list> Gateway clients: all, auto, cursor, claude-code,
|
|
254
|
+
claude-desktop, codex, gemini-cli, windsurf, vscode
|
|
255
|
+
--developer-name <name> Runtime identity for user-scoped policies (auto-detected if omitted)
|
|
256
|
+
--agent-name <name> Runtime agent name (auto-generated from identity + client if omitted)
|
|
257
|
+
--scope <scope> Claude Code MCP scope: local, project, or user
|
|
258
|
+
--claude-code-scope <s> Claude Code scope for install-mcp-gateway
|
|
259
|
+
--cursor-project <bool> Cursor project config for install-mcp-gateway
|
|
260
|
+
--config-path <path> Claude Desktop config override path
|
|
261
|
+
--mcp-auth-type <type> HTTP MCP auth: none, bearer, basic, api-key
|
|
262
|
+
--mcp-token <token> HTTP MCP bearer token
|
|
263
|
+
--mcp-username <user> HTTP MCP basic username
|
|
264
|
+
--mcp-password <pass> HTTP MCP basic password
|
|
265
|
+
--mcp-api-key-header <h> HTTP MCP API-key header name
|
|
266
|
+
--mcp-api-key <key> HTTP MCP API key value
|
|
267
|
+
--rag-path <path> RAG file or directory to scan
|
|
268
|
+
--rag-url <url> Live RAG HTTP endpoint to scan
|
|
269
|
+
--shield-id <id> Shield ID for local outbound Shield verdicts
|
|
270
|
+
--shield-key <key> Optional Shield key for locked Shields
|
|
271
|
+
--fail-on <severity> agent-ci fail threshold: critical, high, medium, low
|
|
272
|
+
--require-gateway agent-ci requires risky MCP servers to use FCD gateway
|
|
273
|
+
--require-approval-for agent-ci risky controls list, e.g. payment,delete,shell,secrets
|
|
274
|
+
--require-upload agent-ci fails if evidence cannot upload to AgentGuard UI
|
|
275
|
+
--changed-only agent-ci limits findings to changed files
|
|
276
|
+
--changed-files <path> file or comma/newline list of changed files for agent-ci
|
|
277
|
+
--method <GET|POST> Local endpoint method
|
|
278
|
+
--request-format <fmt> Local endpoint request format: custom or openai
|
|
279
|
+
--auth-type <type> none, bearer, basic, api-key
|
|
280
|
+
--description <text> Agent description
|
|
281
|
+
--system-prompt <text> System prompt (text or path to file)
|
|
282
|
+
--mode <sync|async> Hosted mode, or local mode: quick, full, targeted, deep
|
|
283
|
+
--categories <list> Comma-separated attack categories
|
|
284
|
+
--attack-count <n> Number of attacks to run
|
|
285
|
+
--surface <list> Discover surfaces: mcp, secrets, agent-files, posture, all
|
|
286
|
+
--fail-threshold <n> Exit code 1 if score below n (default: 0)
|
|
287
|
+
--format <fmt> Output: table, json, summary, report, full-report (default: table)
|
|
288
|
+
--open Open browser scan UI and saved local scan report
|
|
289
|
+
--open-ui Open only the browser scan UI before local execution
|
|
290
|
+
--no-open Do not open the browser during/after local scans
|
|
291
|
+
--webhook-format <fmt> Hosted webhook format, or legacy local request format
|
|
292
|
+
--config <path> Path to .fullcourtdefense.yml config file
|
|
293
|
+
|
|
294
|
+
\x1b[1mExamples:\x1b[0m
|
|
295
|
+
$ fullcourtdefense scan --endpoint https://my-bot.com/chat --description "Support bot"
|
|
296
|
+
$ fullcourtdefense help
|
|
297
|
+
$ fullcourtdefense scan --local
|
|
298
|
+
$ fullcourtdefense scan --local --open-ui
|
|
299
|
+
$ fullcourtdefense scan --local --type endpoint --mode full --endpoint http://internal-agent/chat
|
|
300
|
+
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full
|
|
301
|
+
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp
|
|
302
|
+
$ fullcourtdefense scan --local --type mcp --mcp-url https://internal.company.com/mcp --mcp-tool all --mode full
|
|
303
|
+
$ fullcourtdefense scan --local --type mcp --mcp-transport sse --mcp-url https://internal.company.com/sse --mcp-tool all --mode full
|
|
304
|
+
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
305
|
+
$ fullcourtdefense discover
|
|
306
|
+
$ fullcourtdefense discover --surface mcp
|
|
307
|
+
$ fullcourtdefense discover --surface all --upload
|
|
308
|
+
$ fullcourtdefense discover --surface secrets
|
|
309
|
+
$ fullcourtdefense discover --surface agent-files
|
|
310
|
+
$ fullcourtdefense discover --deep --upload --silent --user-email you@company.com
|
|
311
|
+
$ fullcourtdefense discover --type mcp --json
|
|
312
|
+
$ fullcourtdefense install-cursor-hook
|
|
313
|
+
$ fullcourtdefense install-cursor-hook --shadow true # monitor only
|
|
314
|
+
$ fullcourtdefense install-cursor-hook --events prompt,shell,mcp,file
|
|
315
|
+
$ fullcourtdefense install-cursor-hook --project true # this repo only
|
|
316
|
+
$ fullcourtdefense uninstall-cursor-hook
|
|
317
|
+
$ fullcourtdefense install-claude-hook # Claude Code + VS Code + Copilot CLI
|
|
318
|
+
$ fullcourtdefense install-claude-hook --events tools,prompt # also scan prompts
|
|
319
|
+
$ fullcourtdefense uninstall-claude-hook
|
|
320
|
+
$ fullcourtdefense install-mcp-gateway --clients auto --mcp-command npm --mcp-args "run mcp"
|
|
321
|
+
$ fullcourtdefense install-mcp-gateway --clients all --mcp-command npm --mcp-args "run mcp" --upload
|
|
322
|
+
$ fullcourtdefense install-cursor-mcp-gateway --project true --mcp-command npm --mcp-args "run mcp"
|
|
323
|
+
$ fullcourtdefense install-claude-code-mcp-gateway --scope local --mcp-command npm --mcp-args "run mcp"
|
|
324
|
+
$ fullcourtdefense install-claude-code-mcp-gateway --scope project --mcp-command npm --mcp-args "run mcp"
|
|
325
|
+
$ fullcourtdefense install-claude-desktop-mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
326
|
+
$ fullcourtdefense mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
327
|
+
$ fullcourtdefense login --token <fleet-enrollment-token>
|
|
328
|
+
$ fullcourtdefense install-all
|
|
329
|
+
$ fullcourtdefense install-all --auto-protect true --upload
|
|
330
|
+
$ fullcourtdefense discover --surface all --upload --schedule logon
|
|
331
|
+
$ fullcourtdefense install-mcp-gateway --clients cursor,codex --mcp-command npm --mcp-args "run mcp"
|
|
332
|
+
$ fullcourtdefense install-codex-mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
333
|
+
$ fullcourtdefense scan --system-prompt ./prompts/system.md --fail-threshold 80
|
|
334
|
+
$ fullcourtdefense scan --config .fullcourtdefense.yml --format json
|
|
335
|
+
$ fullcourtdefense credits
|
|
336
|
+
$ fullcourtdefense init
|
|
337
|
+
|
|
338
|
+
\x1b[2mDocs: https://fullcourtdefense.ai/docs/cli\x1b[0m
|
|
339
339
|
`);
|
|
340
340
|
}
|
|
341
341
|
async function main() {
|
package/dist/version.json
CHANGED