clawmoat 0.8.0 → 1.0.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/.dockerignore +9 -0
- package/CHANGELOG.md +18 -0
- package/DEMO.md +87 -0
- package/Dockerfile +5 -18
- package/README.md +232 -8
- package/THREAT_MODEL.md +129 -0
- package/agent/README.md +131 -0
- package/agent/index.js +471 -0
- package/agent/install-service.sh +94 -0
- package/agent/openclaw-hook.js +453 -0
- package/agent/provider-setup.js +649 -0
- package/agent/setup.js +274 -0
- package/assets/BADGE-USAGE.md +20 -0
- package/assets/clawmoat-badge.svg +21 -0
- package/bin/clawmoat.js +468 -111
- package/docs/affiliates/dashboard.html +124 -0
- package/docs/affiliates/index.html +236 -0
- package/docs/agent-install.html +183 -0
- package/docs/ai-agent-security-scanner.html +10 -6
- package/docs/badge/index.html +149 -0
- package/docs/badge/scanning.svg +23 -0
- package/docs/blog/386-malicious-skills.html +11 -4
- package/docs/blog/40000-exposed-openclaw-instances.html +11 -4
- package/docs/blog/agent-trust-protocol.html +5 -4
- package/docs/blog/ai-agent-earns-commissions.html +230 -0
- package/docs/blog/bugmageddon-agent-firewall.html +174 -0
- package/docs/blog/calculator-math.html +180 -0
- package/docs/blog/clawmoat-vs-llamafirewall-nemo-guardrails.html +10 -4
- package/docs/blog/host-guardian-launch.html +18 -8
- package/docs/blog/ibm-experts-agent-runtime-protection.html +15 -6
- package/docs/blog/index.html +67 -9
- package/docs/blog/langchain-security-tutorial.html +18 -8
- package/docs/blog/mcp-30-cves-security-crisis.html +11 -4
- package/docs/blog/meta-researcher-rogue-agent.html +201 -0
- package/docs/blog/microsoft-openclaw-workstation-security.html +5 -4
- package/docs/blog/nist-ai-agent-standards-clawmoat.html +16 -8
- package/docs/blog/oasis-websocket-hijack.html +11 -4
- package/docs/blog/ollama-openclaw-security.html +10 -4
- package/docs/blog/openclaw-enterprise-readiness-claw10.html +5 -4
- package/docs/blog/openclaw-security-reckoning-2026.html +11 -4
- package/docs/blog/owasp-agentic-ai-top10.html +18 -8
- package/docs/blog/securing-ai-agents.html +18 -8
- package/docs/blog/supply-chain-agents.html +18 -8
- package/docs/business/index.html +11 -16
- package/docs/business/install.html +21 -7
- package/docs/checklist.html +10 -4
- package/docs/compare/index.html +122 -0
- package/docs/compare/lakera/index.html +62 -0
- package/docs/compare/llm-guard/index.html +49 -0
- package/docs/compare/snyk-agent-scan/index.html +63 -0
- package/docs/compare.html +10 -6
- package/docs/dashboard/index.html +520 -0
- package/docs/finance/index.html +9 -6
- package/docs/guides/business-deployment.html +770 -0
- package/docs/hall-of-fame.html +11 -5
- package/docs/index.html +266 -137
- package/docs/integrations/langchain.html +14 -6
- package/docs/integrations/openai.html +14 -6
- package/docs/integrations/openclaw.html +55 -7
- package/docs/plans/2026-03-26-threat-intel-api.md +255 -0
- package/docs/plans/2026-04-14-bugmageddon-marketing-pack.md +329 -0
- package/docs/plans/2026-04-14-clawmoat-v1-bugmageddon.md +248 -0
- package/docs/plans/2026-04-14-v1-release-update.md +91 -0
- package/docs/plans/2026-04-19-supabase-audit.md +68 -0
- package/docs/plans/2026-05-12-sales-push.md +303 -0
- package/docs/playground/index.html +893 -0
- package/docs/playground.html +4 -7
- package/docs/rfcs/defense-in-depth.md +467 -0
- package/docs/scan/index.html +156 -12
- package/docs/services/case-study.html +255 -0
- package/docs/services/downloads/install-openclaw.bat +45 -0
- package/docs/services/downloads/install-openclaw.command +38 -0
- package/docs/services/downloads/install-openclaw.sh +38 -0
- package/docs/services/get-started.html +165 -0
- package/docs/services/index.html +598 -0
- package/docs/services/multi-agent-security.html +284 -0
- package/docs/services/one-pager.html +99 -0
- package/docs/services/pitch-deck.html +229 -0
- package/docs/services/roi-calculator.html +258 -0
- package/docs/sitemap.xml +62 -2
- package/docs/support/index.html +12 -1
- package/docs/templates/customer-service/HEARTBEAT.md +61 -0
- package/docs/templates/customer-service/MEMORY.md +89 -0
- package/docs/templates/customer-service/SOUL.md +41 -0
- package/docs/templates/customer-service/USER.md +56 -0
- package/docs/templates/executive/HEARTBEAT.md +86 -0
- package/docs/templates/executive/MEMORY.md +92 -0
- package/docs/templates/executive/SOUL.md +44 -0
- package/docs/templates/executive/USER.md +62 -0
- package/docs/templates/finance/HEARTBEAT.md +58 -0
- package/docs/templates/finance/MEMORY.md +87 -0
- package/docs/templates/finance/SOUL.md +38 -0
- package/docs/templates/finance/USER.md +53 -0
- package/docs/templates/index.html +115 -0
- package/docs/templates/operations/HEARTBEAT.md +63 -0
- package/docs/templates/operations/MEMORY.md +68 -0
- package/docs/templates/operations/SOUL.md +38 -0
- package/docs/templates/operations/USER.md +49 -0
- package/docs/templates/sales/HEARTBEAT.md +55 -0
- package/docs/templates/sales/MEMORY.md +89 -0
- package/docs/templates/sales/SOUL.md +34 -0
- package/docs/templates/sales/USER.md +54 -0
- package/eslint.config.js +32 -0
- package/evals/README.md +29 -0
- package/evals/cases.json +390 -0
- package/evals/results.md +68 -0
- package/evals/run.js +180 -0
- package/examples/demo-attack/demo.js +186 -0
- package/examples/python-quickstart/README.md +54 -0
- package/examples/python-quickstart/clawmoat_client.py +167 -0
- package/examples/video-demo/README.md +14 -0
- package/examples/video-demo/scene-a-normal.js +29 -0
- package/examples/video-demo/scene-b-attack-arrives.js +31 -0
- package/examples/video-demo/scene-c-hijack.js +44 -0
- package/examples/video-demo/scene-d-clawmoat.js +46 -0
- package/integrations/crewai/README.md +32 -0
- package/integrations/crewai/clawmoat_crewai/__init__.py +17 -0
- package/integrations/crewai/clawmoat_crewai/guard.py +103 -0
- package/integrations/crewai/pyproject.toml +21 -0
- package/integrations/langchain/README.md +91 -0
- package/integrations/langchain/clawmoat_langchain/__init__.py +17 -0
- package/integrations/langchain/clawmoat_langchain/callback.py +489 -0
- package/integrations/langchain/pyproject.toml +32 -0
- package/integrations/litellm/README.md +324 -0
- package/integrations/litellm/clawmoat_litellm/__init__.py +21 -0
- package/integrations/litellm/clawmoat_litellm/callback.py +329 -0
- package/integrations/litellm/clawmoat_litellm/proxy_middleware.py +224 -0
- package/integrations/litellm/pyproject.toml +74 -0
- package/integrations/openai-agents/README.md +392 -0
- package/integrations/openai-agents/clawmoat_openai_agents/__init__.py +20 -0
- package/integrations/openai-agents/clawmoat_openai_agents/guardrail.py +431 -0
- package/integrations/openai-agents/clawmoat_openai_agents/middleware.py +311 -0
- package/integrations/openai-agents/pyproject.toml +76 -0
- package/package.json +6 -5
- package/plugins/openclaw-adapter/PHASE1.md +439 -0
- package/plugins/openclaw-adapter/README.md +103 -0
- package/plugins/openclaw-adapter/SPEC.md +1644 -0
- package/plugins/openclaw-adapter/package.json +31 -0
- package/plugins/openclaw-adapter/src/index.test.ts +226 -0
- package/plugins/openclaw-adapter/src/index.ts +140 -0
- package/plugins/openclaw-adapter/tsconfig.json +14 -0
- package/server/data/threats.json +290 -0
- package/server/index.js +142 -7
- package/src/adapters/express.js +161 -0
- package/src/adapters/index.js +92 -0
- package/src/adapters/langchain.js +185 -0
- package/src/approval/index.js +456 -0
- package/src/ban-scanner.js +200 -0
- package/src/boundary-scanner.js +296 -0
- package/src/ci-scanner.js +279 -0
- package/src/code-scanner.js +245 -0
- package/src/enforce.js +166 -0
- package/src/formatters/json.js +80 -0
- package/src/formatters/sarif.js +388 -0
- package/src/guardian/alerts.js +34 -3
- package/src/guardian/index.js +41 -2
- package/src/index.js +102 -0
- package/src/integrations/agentmesh.js +501 -0
- package/src/language-detector.js +201 -0
- package/src/mcp-scanner.js +253 -0
- package/src/multimodal/index.js +579 -0
- package/src/obfuscation-scanner.js +457 -0
- package/src/policy-engine.js +402 -0
- package/src/scanners/dependency-attacks.js +128 -0
- package/src/scanners/prompt-injection.js +18 -0
- package/src/scanners/supply-chain.js +14 -0
- package/src/templates/default-config.yml +90 -0
- package/src/vuln-ops/exploitability.js +46 -0
- package/src/watch/live-monitor.js +720 -0
- package/clawmoat-0.8.0.tgz +0 -0
- package/server/index.js.patch +0 -1
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawMoat MCP Scanner — Discover and scan MCP server configurations
|
|
3
|
+
* Finds configs for Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Gemini CLI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
|
|
10
|
+
const HOME = os.homedir();
|
|
11
|
+
|
|
12
|
+
// Known MCP config locations
|
|
13
|
+
const MCP_CONFIG_PATHS = [
|
|
14
|
+
// Claude Desktop
|
|
15
|
+
{ name: 'Claude Desktop', path: path.join(HOME, '.claude', 'claude_desktop_config.json') },
|
|
16
|
+
{ name: 'Claude Desktop (macOS)', path: path.join(HOME, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json') },
|
|
17
|
+
{ name: 'Claude Desktop (Windows)', path: path.join(HOME, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json') },
|
|
18
|
+
// Claude Code
|
|
19
|
+
{ name: 'Claude Code', path: path.join(HOME, '.claude', 'mcp.json') },
|
|
20
|
+
{ name: 'Claude Code (project)', path: '.claude/mcp.json' },
|
|
21
|
+
// Cursor
|
|
22
|
+
{ name: 'Cursor', path: path.join(HOME, '.cursor', 'mcp.json') },
|
|
23
|
+
// VS Code
|
|
24
|
+
{ name: 'VS Code', path: path.join(HOME, '.vscode', 'mcp.json') },
|
|
25
|
+
{ name: 'VS Code (settings)', path: path.join(HOME, '.config', 'Code', 'User', 'settings.json') },
|
|
26
|
+
// Windsurf
|
|
27
|
+
{ name: 'Windsurf', path: path.join(HOME, '.windsurf', 'mcp.json') },
|
|
28
|
+
{ name: 'Windsurf (codeium)', path: path.join(HOME, '.codeium', 'windsurf', 'mcp_config.json') },
|
|
29
|
+
// Gemini CLI
|
|
30
|
+
{ name: 'Gemini CLI', path: path.join(HOME, '.gemini', 'settings.json') },
|
|
31
|
+
// OpenClaw
|
|
32
|
+
{ name: 'OpenClaw', path: path.join(HOME, '.openclaw', 'openclaw.json') },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Dangerous patterns in MCP server configs
|
|
36
|
+
const MCP_RISKS = [
|
|
37
|
+
// Command execution
|
|
38
|
+
{ id: 'mcp-arbitrary-cmd', severity: 'critical', pattern: (server) => {
|
|
39
|
+
const cmd = server.command || '';
|
|
40
|
+
const args = (server.args || []).join(' ');
|
|
41
|
+
return /^(bash|sh|zsh|cmd|powershell|node|python|ruby|perl)$/i.test(cmd) && !/mcp|server/i.test(args);
|
|
42
|
+
}, label: 'Arbitrary command execution', fix: 'MCP server runs a generic shell/interpreter. Use a purpose-built MCP server binary instead.' },
|
|
43
|
+
|
|
44
|
+
// Root filesystem access
|
|
45
|
+
{ id: 'mcp-root-fs', severity: 'critical', pattern: (server) => {
|
|
46
|
+
const args = JSON.stringify(server.args || []);
|
|
47
|
+
return /["\s]\/["\\s,\]]/.test(args) || /allowedDirectories.*["']\/["']/.test(args);
|
|
48
|
+
}, label: 'Root filesystem access', fix: 'MCP server has access to root filesystem. Restrict to specific directories.' },
|
|
49
|
+
|
|
50
|
+
// Home directory access
|
|
51
|
+
{ id: 'mcp-home-fs', severity: 'high', pattern: (server) => {
|
|
52
|
+
const args = JSON.stringify(server.args || []);
|
|
53
|
+
return args.includes(HOME) && /filesystem|fs-|file/i.test(JSON.stringify(server));
|
|
54
|
+
}, label: 'Home directory access via filesystem MCP', fix: 'Restrict filesystem MCP servers to project directories only.' },
|
|
55
|
+
|
|
56
|
+
// Known dangerous MCP servers
|
|
57
|
+
{ id: 'mcp-dangerous-server', severity: 'high', pattern: (server) => {
|
|
58
|
+
const full = JSON.stringify(server).toLowerCase();
|
|
59
|
+
return /mcp-shell|mcp-terminal|mcp-exec|mcp-command/.test(full);
|
|
60
|
+
}, label: 'Shell/terminal execution MCP server', fix: 'Shell-access MCP servers give agents unrestricted command execution. Remove or heavily restrict.' },
|
|
61
|
+
|
|
62
|
+
// Env var credential exposure
|
|
63
|
+
{ id: 'mcp-env-creds', severity: 'high', pattern: (server) => {
|
|
64
|
+
const env = server.env || {};
|
|
65
|
+
const keys = Object.keys(env);
|
|
66
|
+
return keys.some(k => /key|secret|token|password|auth|credential/i.test(k));
|
|
67
|
+
}, label: 'Credentials in MCP server environment', fix: 'MCP server has API keys/secrets in env vars. These are accessible to any tool the server exposes. Use scoped tokens with minimal permissions.' },
|
|
68
|
+
|
|
69
|
+
// Hardcoded URLs (potential C2)
|
|
70
|
+
{ id: 'mcp-external-url', severity: 'medium', pattern: (server) => {
|
|
71
|
+
const full = JSON.stringify(server);
|
|
72
|
+
const urls = full.match(/https?:\/\/[^\s"']+/g) || [];
|
|
73
|
+
return urls.some(u => !/localhost|127\.0\.0\.1|github\.com|npmjs\.com|pypi\.org/.test(u));
|
|
74
|
+
}, label: 'External URL in MCP config', fix: 'MCP server connects to an external URL. Verify this is a trusted endpoint.' },
|
|
75
|
+
|
|
76
|
+
// stdio with no restrictions
|
|
77
|
+
{ id: 'mcp-unrestricted-stdio', severity: 'medium', pattern: (server) => {
|
|
78
|
+
const transport = server.transport || 'stdio';
|
|
79
|
+
return transport === 'stdio' && !server.allowedTools && !server.blockedTools;
|
|
80
|
+
}, label: 'Unrestricted stdio MCP server', fix: 'MCP server exposes all tools via stdio with no allowlist/blocklist. Add allowedTools to restrict.' },
|
|
81
|
+
|
|
82
|
+
// npx/pip without pinned version
|
|
83
|
+
{ id: 'mcp-unpinned', severity: 'medium', pattern: (server) => {
|
|
84
|
+
const cmd = server.command || '';
|
|
85
|
+
const args = (server.args || []).join(' ');
|
|
86
|
+
if (!/npx|uvx|pip/.test(cmd)) return false;
|
|
87
|
+
// Check if any arg has a version pin (@version or ==version)
|
|
88
|
+
return !/@[\d.]|==[\d.]/.test(args);
|
|
89
|
+
}, label: 'Unpinned MCP server package', fix: 'MCP server installed via npx/uvx without version pin. A supply chain attack could replace the package. Pin to a specific version.' },
|
|
90
|
+
|
|
91
|
+
// Too many tools exposed
|
|
92
|
+
{ id: 'mcp-tool-sprawl', severity: 'low', pattern: (server) => {
|
|
93
|
+
// Can't always detect this statically, but flag servers with no tool restrictions
|
|
94
|
+
return !server.allowedTools && !server.blockedTools && !server.disabledTools;
|
|
95
|
+
}, label: 'No tool restrictions configured', fix: 'Consider using allowedTools/blockedTools to limit which MCP tools the agent can invoke.' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// Known compromised/vulnerable MCP servers
|
|
99
|
+
const KNOWN_VULNERABLE_SERVERS = {
|
|
100
|
+
'@anthropic/mcp-filesystem': { severity: 'medium', note: 'Powerful but broad. Always restrict allowedDirectories.' },
|
|
101
|
+
'mcp-shell': { severity: 'critical', note: 'Gives agents arbitrary shell access. Almost never appropriate.' },
|
|
102
|
+
'mcp-terminal': { severity: 'critical', note: 'Gives agents terminal access. Use with extreme caution.' },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Discover MCP config files on the system
|
|
107
|
+
* @returns {Array<{name: string, path: string, exists: boolean}>}
|
|
108
|
+
*/
|
|
109
|
+
function discoverMCPConfigs(extraPaths = []) {
|
|
110
|
+
const allPaths = [...MCP_CONFIG_PATHS, ...extraPaths.map(p => ({ name: 'Custom', path: p }))];
|
|
111
|
+
return allPaths.map(entry => ({
|
|
112
|
+
...entry,
|
|
113
|
+
exists: fs.existsSync(entry.path),
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Parse an MCP config file and extract server definitions
|
|
119
|
+
* @param {string} filePath
|
|
120
|
+
* @returns {Array<{name: string, server: object}>}
|
|
121
|
+
*/
|
|
122
|
+
function parseMCPConfig(filePath) {
|
|
123
|
+
try {
|
|
124
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
125
|
+
const config = JSON.parse(raw);
|
|
126
|
+
const servers = [];
|
|
127
|
+
|
|
128
|
+
// Claude Desktop / Claude Code format: { mcpServers: { name: { command, args, env } } }
|
|
129
|
+
if (config.mcpServers) {
|
|
130
|
+
for (const [name, server] of Object.entries(config.mcpServers)) {
|
|
131
|
+
servers.push({ name, server, source: 'mcpServers' });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// VS Code / Cursor format: { mcp: { servers: { name: { ... } } } }
|
|
136
|
+
if (config.mcp?.servers) {
|
|
137
|
+
for (const [name, server] of Object.entries(config.mcp.servers)) {
|
|
138
|
+
servers.push({ name, server, source: 'mcp.servers' });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Array format: [{ name, command, args }]
|
|
143
|
+
if (Array.isArray(config)) {
|
|
144
|
+
config.forEach((server, i) => {
|
|
145
|
+
servers.push({ name: server.name || `server-${i}`, server, source: 'array' });
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// OpenClaw format: check for mcp section
|
|
150
|
+
if (config.mcp) {
|
|
151
|
+
if (config.mcp.mcpServers) {
|
|
152
|
+
for (const [name, server] of Object.entries(config.mcp.mcpServers)) {
|
|
153
|
+
servers.push({ name, server, source: 'openclaw.mcp.mcpServers' });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return servers;
|
|
159
|
+
} catch (e) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Scan a single MCP server definition for risks
|
|
166
|
+
* @param {string} serverName
|
|
167
|
+
* @param {object} serverConfig
|
|
168
|
+
* @returns {Array<{id: string, severity: string, label: string, fix: string}>}
|
|
169
|
+
*/
|
|
170
|
+
function scanMCPServer(serverName, serverConfig) {
|
|
171
|
+
const findings = [];
|
|
172
|
+
|
|
173
|
+
// Check against risk patterns
|
|
174
|
+
for (const risk of MCP_RISKS) {
|
|
175
|
+
try {
|
|
176
|
+
if (risk.pattern(serverConfig)) {
|
|
177
|
+
findings.push({
|
|
178
|
+
id: risk.id,
|
|
179
|
+
severity: risk.severity,
|
|
180
|
+
label: risk.label,
|
|
181
|
+
fix: risk.fix,
|
|
182
|
+
server: serverName,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
} catch (e) { /* pattern failed, skip */ }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check against known vulnerable servers
|
|
189
|
+
const cmd = serverConfig.command || '';
|
|
190
|
+
const args = (serverConfig.args || []).join(' ');
|
|
191
|
+
const fullCmd = `${cmd} ${args}`;
|
|
192
|
+
for (const [pkg, info] of Object.entries(KNOWN_VULNERABLE_SERVERS)) {
|
|
193
|
+
if (fullCmd.includes(pkg)) {
|
|
194
|
+
findings.push({
|
|
195
|
+
id: 'mcp-known-vulnerable',
|
|
196
|
+
severity: info.severity,
|
|
197
|
+
label: `Known risky MCP server: ${pkg}`,
|
|
198
|
+
fix: info.note,
|
|
199
|
+
server: serverName,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return findings;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Full MCP scan — discover configs, parse, and scan all servers
|
|
209
|
+
* @param {object} options
|
|
210
|
+
* @returns {object} Scan report
|
|
211
|
+
*/
|
|
212
|
+
function scanMCP(options = {}) {
|
|
213
|
+
const { extraPaths = [], verbose = false } = options;
|
|
214
|
+
const report = {
|
|
215
|
+
timestamp: new Date().toISOString(),
|
|
216
|
+
configsFound: [],
|
|
217
|
+
servers: [],
|
|
218
|
+
findings: [],
|
|
219
|
+
summary: { total: 0, critical: 0, high: 0, medium: 0, low: 0 },
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Discover configs
|
|
223
|
+
const configs = discoverMCPConfigs(extraPaths);
|
|
224
|
+
report.configsFound = configs.filter(c => c.exists);
|
|
225
|
+
|
|
226
|
+
// Parse and scan each config
|
|
227
|
+
for (const config of report.configsFound) {
|
|
228
|
+
const servers = parseMCPConfig(config.path);
|
|
229
|
+
for (const { name, server, source } of servers) {
|
|
230
|
+
report.servers.push({ name, config: config.name, path: config.path, source });
|
|
231
|
+
const findings = scanMCPServer(name, server);
|
|
232
|
+
for (const f of findings) {
|
|
233
|
+
f.configName = config.name;
|
|
234
|
+
f.configPath = config.path;
|
|
235
|
+
report.findings.push(f);
|
|
236
|
+
report.summary.total++;
|
|
237
|
+
report.summary[f.severity]++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return report;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = {
|
|
246
|
+
discoverMCPConfigs,
|
|
247
|
+
parseMCPConfig,
|
|
248
|
+
scanMCPServer,
|
|
249
|
+
scanMCP,
|
|
250
|
+
MCP_CONFIG_PATHS,
|
|
251
|
+
MCP_RISKS,
|
|
252
|
+
KNOWN_VULNERABLE_SERVERS,
|
|
253
|
+
};
|