fullcourtdefense-cli 1.1.17 → 1.3.0
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/README.md +33 -0
- package/dist/commands/discover.d.ts +22 -0
- package/dist/commands/discover.js +283 -66
- package/dist/commands/discoverPaths.d.ts +18 -0
- package/dist/commands/discoverPaths.js +194 -0
- package/dist/commands/discoverProxy.d.ts +42 -0
- package/dist/commands/discoverProxy.js +256 -0
- package/dist/commands/discoverSchedule.d.ts +6 -0
- package/dist/commands/discoverSchedule.js +132 -0
- package/dist/commands/knownMcpServers.d.ts +8 -0
- package/dist/commands/knownMcpServers.js +68 -0
- package/dist/commands/mcpGateway.d.ts +2 -0
- package/dist/commands/mcpGateway.js +20 -81
- package/dist/index.js +13 -3
- package/package.json +2 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.knownMcpServerInfo = knownMcpServerInfo;
|
|
4
|
+
exports.directServerFixHint = directServerFixHint;
|
|
5
|
+
const KNOWN = [
|
|
6
|
+
{
|
|
7
|
+
match: /playwright/i,
|
|
8
|
+
info: {
|
|
9
|
+
title: 'Playwright',
|
|
10
|
+
description: 'Browser automation — AI can open sites, click, and act as the logged-in user.',
|
|
11
|
+
category: 'browser',
|
|
12
|
+
recommendGateway: true,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
match: /puppeteer|selenium|browser/i,
|
|
17
|
+
info: {
|
|
18
|
+
title: 'Browser automation',
|
|
19
|
+
description: 'Controls a web browser on the developer machine.',
|
|
20
|
+
category: 'browser',
|
|
21
|
+
recommendGateway: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
match: /filesystem|server-filesystem/i,
|
|
26
|
+
info: {
|
|
27
|
+
title: 'Filesystem',
|
|
28
|
+
description: 'Reads and writes local files — high exfiltration risk.',
|
|
29
|
+
category: 'filesystem',
|
|
30
|
+
recommendGateway: true,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
match: /postgres|mysql|sqlite|database|supabase/i,
|
|
35
|
+
info: {
|
|
36
|
+
title: 'Database',
|
|
37
|
+
description: 'Queries databases directly from the AI client.',
|
|
38
|
+
category: 'database',
|
|
39
|
+
recommendGateway: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
match: /agentguard-gateway|fullcourtdefense-gateway|fcd-gateway/i,
|
|
44
|
+
info: {
|
|
45
|
+
title: 'FCD MCP gateway',
|
|
46
|
+
description: 'Full Court Defense proxy — tool calls checked by Shield and Action Policies.',
|
|
47
|
+
category: 'gateway',
|
|
48
|
+
recommendGateway: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
function knownMcpServerInfo(serverName, command) {
|
|
53
|
+
const hay = `${serverName} ${command || ''}`;
|
|
54
|
+
for (const entry of KNOWN) {
|
|
55
|
+
if (entry.match.test(hay))
|
|
56
|
+
return entry.info;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function directServerFixHint(serverName) {
|
|
61
|
+
const info = knownMcpServerInfo(serverName);
|
|
62
|
+
if (!info?.recommendGateway)
|
|
63
|
+
return undefined;
|
|
64
|
+
if (/playwright/i.test(serverName)) {
|
|
65
|
+
return 'Remove Playwright from mcp.json or route it through: fullcourtdefense install-mcp-gateway --clients all --mcp-command ...';
|
|
66
|
+
}
|
|
67
|
+
return 'Route through FCD gateway: fullcourtdefense install-mcp-gateway --clients all --mcp-command npm --mcp-args "run mcp"';
|
|
68
|
+
}
|
|
@@ -34,6 +34,8 @@ export interface InstallMcpGatewayArgs extends McpGatewayArgs {
|
|
|
34
34
|
cursorProject?: string;
|
|
35
35
|
claudeCodeScope?: string;
|
|
36
36
|
serverName?: string;
|
|
37
|
+
upload?: string;
|
|
38
|
+
apiKey?: string;
|
|
37
39
|
}
|
|
38
40
|
export declare function mcpGatewayCommand(args: McpGatewayArgs, config: BotGuardConfig): Promise<void>;
|
|
39
41
|
export declare function installCursorMcpGatewayCommand(args: InstallCursorMcpGatewayArgs, config: BotGuardConfig): Promise<void>;
|
|
@@ -42,6 +42,8 @@ const fs = __importStar(require("fs"));
|
|
|
42
42
|
const os = __importStar(require("os"));
|
|
43
43
|
const path = __importStar(require("path"));
|
|
44
44
|
const child_process_1 = require("child_process");
|
|
45
|
+
const discoverPaths_1 = require("./discoverPaths");
|
|
46
|
+
const discover_1 = require("./discover");
|
|
45
47
|
const DEFAULT_API_URL = 'https://api.fullcourtdefense.ai';
|
|
46
48
|
const MANAGED_SERVER_NAME = 'agentguard-gateway';
|
|
47
49
|
function parseArgsList(value) {
|
|
@@ -672,83 +674,6 @@ function writeMcpServerConfig(file, serverName, nodeExe, commandArgs) {
|
|
|
672
674
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
673
675
|
fs.writeFileSync(file, `${JSON.stringify(json, null, 2)}\n`, 'utf8');
|
|
674
676
|
}
|
|
675
|
-
function dedupePaths(candidates) {
|
|
676
|
-
const seen = new Set();
|
|
677
|
-
return candidates.filter(candidate => {
|
|
678
|
-
const key = path.resolve(candidate.file).toLowerCase();
|
|
679
|
-
if (seen.has(key))
|
|
680
|
-
return false;
|
|
681
|
-
seen.add(key);
|
|
682
|
-
return true;
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
function claudeDesktopMcpPath() {
|
|
686
|
-
const home = os.homedir();
|
|
687
|
-
if (process.platform === 'win32') {
|
|
688
|
-
const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
|
|
689
|
-
return path.join(appData, 'Claude', 'claude_desktop_config.json');
|
|
690
|
-
}
|
|
691
|
-
if (process.platform === 'darwin') {
|
|
692
|
-
return path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
693
|
-
}
|
|
694
|
-
const xdg = process.env.XDG_CONFIG_HOME || path.join(home, '.config');
|
|
695
|
-
return path.join(xdg, 'Claude', 'claude_desktop_config.json');
|
|
696
|
-
}
|
|
697
|
-
function claudeDesktopMsixCandidates() {
|
|
698
|
-
if (process.platform !== 'win32')
|
|
699
|
-
return [];
|
|
700
|
-
const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
701
|
-
const packagesDir = path.join(localAppData, 'Packages');
|
|
702
|
-
let packageNames = [];
|
|
703
|
-
try {
|
|
704
|
-
packageNames = fs.readdirSync(packagesDir)
|
|
705
|
-
.filter(name => /^Claude_/i.test(name));
|
|
706
|
-
}
|
|
707
|
-
catch {
|
|
708
|
-
return [];
|
|
709
|
-
}
|
|
710
|
-
return packageNames.map(name => {
|
|
711
|
-
const file = path.join(packagesDir, name, 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json');
|
|
712
|
-
return {
|
|
713
|
-
file,
|
|
714
|
-
source: 'Claude Desktop (Microsoft Store/MSIX)',
|
|
715
|
-
exists: fs.existsSync(file),
|
|
716
|
-
};
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
function claudeDesktopMcpCandidates() {
|
|
720
|
-
const documented = claudeDesktopMcpPath();
|
|
721
|
-
const normal = {
|
|
722
|
-
file: documented,
|
|
723
|
-
source: process.platform === 'win32'
|
|
724
|
-
? 'Claude Desktop (Windows documented AppData)'
|
|
725
|
-
: process.platform === 'darwin'
|
|
726
|
-
? 'Claude Desktop (macOS)'
|
|
727
|
-
: 'Claude Desktop (Linux/XDG)',
|
|
728
|
-
exists: fs.existsSync(documented),
|
|
729
|
-
};
|
|
730
|
-
// Store/MSIX Claude Desktop reads a virtualized AppData path. Prefer it when present.
|
|
731
|
-
return dedupePaths([
|
|
732
|
-
...claudeDesktopMsixCandidates(),
|
|
733
|
-
normal,
|
|
734
|
-
]);
|
|
735
|
-
}
|
|
736
|
-
function claudeDesktopInstallTargets(configPath) {
|
|
737
|
-
if (configPath) {
|
|
738
|
-
const file = path.resolve(configPath);
|
|
739
|
-
return [{ file, source: 'Claude Desktop (custom config path)', exists: fs.existsSync(file) }];
|
|
740
|
-
}
|
|
741
|
-
const candidates = claudeDesktopMcpCandidates();
|
|
742
|
-
const existing = candidates.filter(candidate => candidate.exists);
|
|
743
|
-
if (existing.length > 0)
|
|
744
|
-
return existing;
|
|
745
|
-
const msix = candidates.find(candidate => candidate.source.includes('MSIX'));
|
|
746
|
-
return [msix || candidates[candidates.length - 1] || {
|
|
747
|
-
file: claudeDesktopMcpPath(),
|
|
748
|
-
source: 'Claude Desktop',
|
|
749
|
-
exists: false,
|
|
750
|
-
}];
|
|
751
|
-
}
|
|
752
677
|
function normalizeClaudeCodeScope(scope) {
|
|
753
678
|
if (scope === 'project' || scope === 'user' || scope === 'local')
|
|
754
679
|
return scope;
|
|
@@ -791,9 +716,8 @@ function detectInstallClients(cursorProject) {
|
|
|
791
716
|
clients.push('cursor');
|
|
792
717
|
if (commandAvailable('claude'))
|
|
793
718
|
clients.push('claude-code');
|
|
794
|
-
if (
|
|
719
|
+
if ((0, discoverPaths_1.claudeDesktopLikelyInstalled)())
|
|
795
720
|
clients.push('claude-desktop');
|
|
796
|
-
}
|
|
797
721
|
return clients;
|
|
798
722
|
}
|
|
799
723
|
function clientInstallArgs(args) {
|
|
@@ -841,7 +765,9 @@ async function installCursorMcpGatewayCommand(args, config) {
|
|
|
841
765
|
async function installMcpGatewayCommand(args, config) {
|
|
842
766
|
const cursorProject = args.cursorProject === 'true';
|
|
843
767
|
const selection = parseClientList(args.clients);
|
|
844
|
-
const clients = selection === 'auto'
|
|
768
|
+
const clients = selection === 'auto'
|
|
769
|
+
? detectInstallClients(cursorProject)
|
|
770
|
+
: selection;
|
|
845
771
|
if (clients.length === 0) {
|
|
846
772
|
throw new Error('No supported MCP clients detected. Re-run with --clients all or a comma list such as cursor,claude-desktop.');
|
|
847
773
|
}
|
|
@@ -876,6 +802,19 @@ async function installMcpGatewayCommand(args, config) {
|
|
|
876
802
|
console.log(`Runtime identity: ${detectedDeveloperName(args)}`);
|
|
877
803
|
console.log('Restart/reload each client to use the protected tools.');
|
|
878
804
|
console.log('Smoke test prompt: "Use lookup_customer to look up customer C-1001."');
|
|
805
|
+
if (args.upload === 'true') {
|
|
806
|
+
console.log('');
|
|
807
|
+
console.log('Uploading desktop inventory to AI Inventory…');
|
|
808
|
+
await (0, discover_1.runDiscoverUpload)({
|
|
809
|
+
apiKey: args.apiKey || config.apiKey,
|
|
810
|
+
apiUrl: args.apiUrl,
|
|
811
|
+
userEmail: args.developerName,
|
|
812
|
+
silent: false,
|
|
813
|
+
}, config);
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
console.log('Run with --upload to refresh AI Inventory / Desktop MCP coverage in the app.');
|
|
817
|
+
}
|
|
879
818
|
}
|
|
880
819
|
async function installClaudeCodeMcpGatewayCommand(args, config) {
|
|
881
820
|
const gatewayConfig = resolveGatewayConfig(args, config, {
|
|
@@ -940,7 +879,7 @@ async function installClaudeDesktopMcpGatewayCommand(args, config) {
|
|
|
940
879
|
agentNamePrefix: 'claude-desktop',
|
|
941
880
|
userObjective: 'Developer requested this action from Claude Desktop.',
|
|
942
881
|
});
|
|
943
|
-
const targets = claudeDesktopInstallTargets(args.configPath);
|
|
882
|
+
const targets = (0, discoverPaths_1.claudeDesktopInstallTargets)(args.configPath);
|
|
944
883
|
const nodeExe = process.execPath;
|
|
945
884
|
const serverName = args.serverName || MANAGED_SERVER_NAME;
|
|
946
885
|
const downstreamCommand = args.mcpCommand || process.env.FCD_MCP_COMMAND;
|
package/dist/index.js
CHANGED
|
@@ -66,8 +66,9 @@ function printHelp() {
|
|
|
66
66
|
configure Saves Shield ID, Shield key, and API URL to .fullcourtdefense.yml.
|
|
67
67
|
scan Runs the scan. Use --local for inside-organization scans.
|
|
68
68
|
discover Finds MCP servers configured on this machine (Cursor, Claude,
|
|
69
|
-
VS Code, Windsurf) and reports their risk.
|
|
70
|
-
them to your AI Inventory.
|
|
69
|
+
VS Code, Windsurf, Codex, Gemini CLI) and reports their risk.
|
|
70
|
+
Use --upload to add them to your AI Inventory. Use --deep for
|
|
71
|
+
live HTTP/SSE tools/list. Use --silent for fleet/MDM scripts.
|
|
71
72
|
install-cursor-hook
|
|
72
73
|
Installs a Cursor hook so every AI prompt + agent action
|
|
73
74
|
(shell, MCP) on this machine is scanned by your Shield.
|
|
@@ -199,6 +200,7 @@ function printHelp() {
|
|
|
199
200
|
$ fullcourtdefense scan --local --type mcp --mcp-command node --mcp-args ./server.js --mcp-tool all --mode full --format report
|
|
200
201
|
$ fullcourtdefense discover
|
|
201
202
|
$ fullcourtdefense discover --upload
|
|
203
|
+
$ fullcourtdefense discover --deep --upload --silent --user-email you@company.com
|
|
202
204
|
$ fullcourtdefense discover --type mcp --json
|
|
203
205
|
$ fullcourtdefense install-cursor-hook --shield-id <id> --shield-key <key>
|
|
204
206
|
$ fullcourtdefense install-cursor-hook --shadow true # monitor only
|
|
@@ -206,7 +208,7 @@ function printHelp() {
|
|
|
206
208
|
$ fullcourtdefense install-cursor-hook --project true # this repo only
|
|
207
209
|
$ fullcourtdefense uninstall-cursor-hook
|
|
208
210
|
$ fullcourtdefense install-mcp-gateway --clients auto --shield-id <id> --shield-key <key> --mcp-command npm --mcp-args "run mcp"
|
|
209
|
-
$ fullcourtdefense install-mcp-gateway --clients all --mcp-command
|
|
211
|
+
$ fullcourtdefense install-mcp-gateway --clients all --shield-id <id> --shield-key <key> --mcp-command npm --mcp-args "run mcp" --upload --api-key <key>
|
|
210
212
|
$ fullcourtdefense install-cursor-mcp-gateway --project true --shield-id <id> --shield-key <key> --mcp-command npm --mcp-args "run mcp"
|
|
211
213
|
$ fullcourtdefense install-claude-code-mcp-gateway --scope local --shield-id <id> --shield-key <key> --mcp-command npm --mcp-args "run mcp"
|
|
212
214
|
$ fullcourtdefense install-claude-code-mcp-gateway --scope project --shield-id <id> --mcp-command npm --mcp-args "run mcp"
|
|
@@ -320,6 +322,12 @@ async function main() {
|
|
|
320
322
|
upload: flags.upload,
|
|
321
323
|
connectorName: flags['connector-name'],
|
|
322
324
|
extraPath: flags.path,
|
|
325
|
+
deep: flags.deep,
|
|
326
|
+
silent: flags.silent,
|
|
327
|
+
userEmail: flags['user-email'],
|
|
328
|
+
schedule: flags.schedule,
|
|
329
|
+
unschedule: flags.unschedule,
|
|
330
|
+
scheduleHour: flags['schedule-hour'],
|
|
323
331
|
};
|
|
324
332
|
await (0, discover_1.discoverCommand)(args, config);
|
|
325
333
|
break;
|
|
@@ -398,6 +406,8 @@ async function main() {
|
|
|
398
406
|
approvalPollMs: flags['approval-poll-ms'],
|
|
399
407
|
scanResponse: flags['scan-response'],
|
|
400
408
|
failClosed: flags['fail-closed'],
|
|
409
|
+
upload: flags.upload,
|
|
410
|
+
apiKey: flags['api-key'],
|
|
401
411
|
};
|
|
402
412
|
await (0, mcpGateway_1.installMcpGatewayCommand)(args, config);
|
|
403
413
|
break;
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fullcourtdefense-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"fullcourtdefense": "dist/index.js",
|
|
8
|
+
"fcd": "dist/index.js",
|
|
8
9
|
"botguard": "dist/index.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|