fullcourtdefense-cli 1.7.24 → 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.
@@ -393,6 +393,10 @@ function mcpServerName(p) {
393
393
  * `perServerAgentName`, so ONE per-agent policy matches the same server across every runtime.
394
394
  * The client is still reported separately as `agentClient` metadata for optional per-runtime
395
395
  * constraints. Non-MCP events keep the collapsed per-developer IDE-runtime identity.
396
+ *
397
+ * The IDE-runtime identity is MACHINE-FREE (`<client>-<username>`, e.g. `cursor-boazl`):
398
+ * safeIdentityPart strips the `@hostname` part, so the same user's IDE on two laptops is
399
+ * ONE agent. Machine attribution stays in the separate `machineName` metadata field.
396
400
  */
397
401
  function agentNameForCall(event, p, client = 'cursor') {
398
402
  if (event === 'mcp') {
@@ -400,7 +404,7 @@ function agentNameForCall(event, p, client = 'cursor') {
400
404
  if (server)
401
405
  return `${safeIdentityPart(developerId())}-${safeIdentityPart(server)}`;
402
406
  }
403
- return `${client}-${developerId()}`;
407
+ return `${client}-${safeIdentityPart(developerId())}`;
404
408
  }
405
409
  /** Cursor conversation/session id when present, else a stable per-machine id. */
406
410
  function sessionId(p) {
@@ -768,10 +768,23 @@ function buildGatewayCommandArgs(gatewayConfig, downstreamCommand, downstreamArg
768
768
  '--fail-closed', String(gatewayConfig.failClosed),
769
769
  ];
770
770
  if (!options.omitSavedCredentials) {
771
- commandArgs.push('--shield-id', gatewayConfig.shieldId);
772
- if (gatewayConfig.shieldKey && options.includeShieldKey !== false) {
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
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.7.24"
2
+ "version": "1.7.26"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.7.24",
3
+ "version": "1.7.26",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {