agent-security-scanner-mcp 3.10.1 → 3.10.3
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/package.json +1 -1
- package/src/cli/doctor.js +13 -0
- package/src/daemon-client.js +1 -1
- package/src/tools/scan-security.js +23 -1
- package/src/utils.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-security-scanner-mcp",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.3",
|
|
4
4
|
"mcpName": "io.github.sinewaveai/agent-security-scanner-mcp",
|
|
5
5
|
"description": "Security scanner MCP server for AI coding agents. Prompt injection firewall, package hallucination detection (4.3M+ packages), 1000+ vulnerability rules with AST & taint analysis, auto-fix. For Claude Code, Cursor, Windsurf, Cline, OpenClaw.",
|
|
6
6
|
"main": "index.js",
|
package/src/cli/doctor.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync, existsSync, writeFileSync, copyFileSync, mkdirSync } from
|
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
4
|
import { homedir, platform } from "os";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { getDaemonClient } from '../daemon-client.js';
|
|
6
7
|
|
|
7
8
|
// Handle both ESM and CJS bundling (Smithery bundles to CJS)
|
|
8
9
|
let __dirname;
|
|
@@ -158,6 +159,18 @@ export async function runDoctor(args) {
|
|
|
158
159
|
console.log(` \u26a0 daemon.py not found (daemon mode unavailable, sync fallback will be used)`);
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
// 3c. Daemon live health check
|
|
163
|
+
if (existsSync(daemonPath) && pythonCmd) {
|
|
164
|
+
try {
|
|
165
|
+
const client = getDaemonClient();
|
|
166
|
+
const health = await client.health();
|
|
167
|
+
console.log(` \u2713 Daemon responding (pid=${health.pid}, cache=${health.cache_size}, uptime=${health.uptime.toFixed(1)}s)`);
|
|
168
|
+
await client.shutdown();
|
|
169
|
+
} catch (e) {
|
|
170
|
+
console.log(` \u26a0 Daemon health check failed: ${e.message}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
161
174
|
// 4. Python can import yaml (analyzer dependency check)
|
|
162
175
|
if (pythonCmd && existsSync(analyzerPath)) {
|
|
163
176
|
const yamlCheck = checkCommand(pythonCmd, ['-c', 'import yaml; print("ok")']);
|
package/src/daemon-client.js
CHANGED
|
@@ -13,7 +13,7 @@ try {
|
|
|
13
13
|
|
|
14
14
|
const DAEMON_SCRIPT = join(__dirname, '..', 'daemon.py');
|
|
15
15
|
const READY_TIMEOUT = 15000; // 15s to wait for __ready__ signal
|
|
16
|
-
const REQUEST_TIMEOUT =
|
|
16
|
+
const REQUEST_TIMEOUT = 45000; // 45s per request (increased for large files in Codex/complex analysis)
|
|
17
17
|
const MAX_RESTARTS = 3;
|
|
18
18
|
const RESTART_WINDOW = 60000; // 60s window for restart counting
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/tools/scan-security.js
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
4
4
|
import { dirname } from "path";
|
|
5
5
|
import { detectLanguage, runAnalyzerAsync, generateFix, toSarif, getEngineMode, extractImports, isTestFile } from '../utils.js';
|
|
6
6
|
import { deduplicateFindings } from '../dedup.js';
|
|
@@ -8,6 +8,8 @@ import { applyContextFilter, detectFrameworks, applyFrameworkAdjustments } from
|
|
|
8
8
|
import { loadConfig, shouldExcludeFile, applyConfig } from '../config.js';
|
|
9
9
|
import { discoverProjectContext } from './project-context.js';
|
|
10
10
|
|
|
11
|
+
const MAX_FILE_SIZE = 1024 * 1024; // 1MB - skip files larger than this to avoid timeouts
|
|
12
|
+
|
|
11
13
|
export const scanSecuritySchema = {
|
|
12
14
|
file_path: z.string().describe("Path to the file to scan"),
|
|
13
15
|
output_format: z.enum(['json', 'sarif']).optional().describe("Output format: 'json' (default) or 'sarif' for GitHub/GitLab integration"),
|
|
@@ -69,6 +71,26 @@ export async function scanSecurity({ file_path, output_format, verbosity, engine
|
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
// Check file size to avoid timeouts on very large files
|
|
75
|
+
try {
|
|
76
|
+
const stats = statSync(file_path);
|
|
77
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
78
|
+
return {
|
|
79
|
+
content: [{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: JSON.stringify({
|
|
82
|
+
file: file_path,
|
|
83
|
+
message: `File too large (${(stats.size / 1024).toFixed(0)}KB). Skipping to avoid timeout. Max size: ${MAX_FILE_SIZE / 1024}KB.`,
|
|
84
|
+
issues_count: 0,
|
|
85
|
+
skipped: true
|
|
86
|
+
})
|
|
87
|
+
}]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
} catch (err) {
|
|
91
|
+
// If stat fails, continue anyway
|
|
92
|
+
}
|
|
93
|
+
|
|
72
94
|
// Load project configuration
|
|
73
95
|
const config = loadConfig(file_path);
|
|
74
96
|
|
package/src/utils.js
CHANGED
|
@@ -86,7 +86,7 @@ export function runAnalyzer(filePath, engine = 'auto') {
|
|
|
86
86
|
}
|
|
87
87
|
const result = execFileSync('python3', args, {
|
|
88
88
|
encoding: 'utf-8',
|
|
89
|
-
timeout:
|
|
89
|
+
timeout: 45000 // Increased to 45s to match daemon timeout
|
|
90
90
|
});
|
|
91
91
|
return JSON.parse(result);
|
|
92
92
|
} catch (error) {
|