agent-security-scanner-mcp 1.0.2 → 1.1.1

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # agent-security-scanner-mcp
2
2
 
3
- A powerful MCP (Model Context Protocol) server for real-time security vulnerability scanning. Integrates with Claude Desktop and Claude Code to automatically detect and fix security issues as you code.
3
+ A powerful MCP (Model Context Protocol) server for real-time security vulnerability scanning. Integrates with Claude Desktop, Claude Code, OpenCode.ai, Kilo Code, and any MCP-compatible client to automatically detect and fix security issues as you code.
4
4
 
5
- **165 Semgrep-aligned security rules | 105 auto-fix templates | 100% fix coverage**
5
+ **165 Semgrep-aligned security rules | 105 auto-fix templates | 100% fix coverage | Package hallucination detection**
6
6
 
7
7
  ## Features
8
8
 
@@ -11,6 +11,7 @@ A powerful MCP (Model Context Protocol) server for real-time security vulnerabil
11
11
  - **Multi-language support** - JavaScript, TypeScript, Python, Java, Go, Dockerfile
12
12
  - **Semgrep-compatible** - Rules aligned with Semgrep registry format
13
13
  - **CWE & OWASP mapped** - Every rule includes CWE and OWASP references
14
+ - **Hallucination detection** - Detect AI-invented package names (Dart, Perl, Raku)
14
15
 
15
16
  ## Installation
16
17
 
@@ -65,6 +66,82 @@ Add to your MCP settings (`~/.claude/settings.json`):
65
66
  }
66
67
  ```
67
68
 
69
+ ### OpenCode.ai
70
+
71
+ Add to your `opencode.jsonc` configuration file:
72
+
73
+ ```json
74
+ {
75
+ "$schema": "https://opencode.ai/config.json",
76
+ "mcp": {
77
+ "security-scanner": {
78
+ "type": "local",
79
+ "command": ["npx", "-y", "agent-security-scanner-mcp"],
80
+ "enabled": true
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Or if installed globally:
87
+
88
+ ```json
89
+ {
90
+ "mcp": {
91
+ "security-scanner": {
92
+ "type": "local",
93
+ "command": ["agent-security-scanner-mcp"],
94
+ "enabled": true
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### Kilo Code
101
+
102
+ **Global configuration** - Add to VS Code settings `mcp_settings.json`:
103
+
104
+ ```json
105
+ {
106
+ "mcpServers": {
107
+ "security-scanner": {
108
+ "command": "npx",
109
+ "args": ["-y", "agent-security-scanner-mcp"],
110
+ "alwaysAllow": [],
111
+ "disabled": false
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ **Project-level configuration** - Create `.kilocode/mcp.json` in your project root:
118
+
119
+ ```json
120
+ {
121
+ "mcpServers": {
122
+ "security-scanner": {
123
+ "command": "npx",
124
+ "args": ["-y", "agent-security-scanner-mcp"],
125
+ "alwaysAllow": ["scan_security", "list_security_rules"],
126
+ "disabled": false
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ **Windows users** - Use cmd wrapper:
133
+
134
+ ```json
135
+ {
136
+ "mcpServers": {
137
+ "security-scanner": {
138
+ "command": "cmd",
139
+ "args": ["/c", "npx", "-y", "agent-security-scanner-mcp"]
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
68
145
  ## Available Tools
69
146
 
70
147
  ### `scan_security`
@@ -127,6 +204,115 @@ Returns:
127
204
 
128
205
  List all 105 available auto-fix templates.
129
206
 
207
+ ---
208
+
209
+ ## Package Hallucination Detection
210
+
211
+ Detect AI-hallucinated package names that don't exist in official registries. Prevents supply chain attacks where attackers register fake package names suggested by AI.
212
+
213
+ ### `check_package`
214
+
215
+ Check if a single package name is legitimate or potentially hallucinated.
216
+
217
+ ```
218
+ Parameters:
219
+ package_name (string): The package name to verify
220
+ ecosystem (enum): "dart", "perl", "raku", "npm", "pypi"
221
+
222
+ Returns:
223
+ - legitimate: true/false
224
+ - hallucinated: true/false
225
+ - confidence: "high"
226
+ - recommendation: Action to take
227
+ ```
228
+
229
+ **Example:**
230
+ ```json
231
+ {
232
+ "package": "flutter_animations",
233
+ "ecosystem": "dart",
234
+ "legitimate": true,
235
+ "hallucinated": false,
236
+ "confidence": "high",
237
+ "total_known_packages": 64721,
238
+ "recommendation": "Package exists in registry - safe to use"
239
+ }
240
+ ```
241
+
242
+ ### `scan_packages`
243
+
244
+ Scan a code file and detect all potentially hallucinated package imports.
245
+
246
+ ```
247
+ Parameters:
248
+ file_path (string): Path to the file to scan
249
+ ecosystem (enum): "dart", "perl", "raku", "npm", "pypi"
250
+
251
+ Returns:
252
+ - List of all packages found
253
+ - Which are legitimate vs hallucinated
254
+ - Recommendation
255
+ ```
256
+
257
+ **Example output:**
258
+ ```json
259
+ {
260
+ "file": "/path/to/main.dart",
261
+ "ecosystem": "dart",
262
+ "total_packages_found": 5,
263
+ "legitimate_count": 4,
264
+ "hallucinated_count": 1,
265
+ "hallucinated_packages": ["fake_flutter_pkg"],
266
+ "legitimate_packages": ["flutter", "http", "provider", "shared_preferences"],
267
+ "recommendation": "⚠️ Found 1 potentially hallucinated package(s): fake_flutter_pkg"
268
+ }
269
+ ```
270
+
271
+ ### `list_package_stats`
272
+
273
+ Show statistics about loaded package lists.
274
+
275
+ ```json
276
+ {
277
+ "package_lists": [
278
+ { "ecosystem": "dart", "packages_loaded": 64721, "status": "ready" },
279
+ { "ecosystem": "perl", "packages_loaded": 1000, "status": "ready" },
280
+ { "ecosystem": "raku", "packages_loaded": 2626, "status": "ready" }
281
+ ],
282
+ "total_packages": 68347
283
+ }
284
+ ```
285
+
286
+ ### Adding Custom Package Lists
287
+
288
+ Add your own package lists to `packages/` directory:
289
+
290
+ ```bash
291
+ # Format: one package name per line
292
+ packages/
293
+ ├── dart.txt # 64,721 packages
294
+ ├── perl.txt # 1,000 packages
295
+ ├── raku.txt # 2,626 packages
296
+ ├── npm.txt # Add your own
297
+ └── pypi.txt # Add your own
298
+ ```
299
+
300
+ ### Fetching Package Lists
301
+
302
+ ```bash
303
+ # Using the included script
304
+ cd mcp-server
305
+ pip install datasets
306
+ python scripts/fetch-packages.py
307
+ ```
308
+
309
+ Package lists are sourced from:
310
+ - **Dart:** [dchitimalla1/dart-20250529](https://huggingface.co/datasets/dchitimalla1/dart-20250529)
311
+ - **Perl:** [dchitimalla1/perl-20250530](https://huggingface.co/datasets/dchitimalla1/perl-20250530)
312
+ - **Raku:** [dchitimalla1/raku-20250523](https://huggingface.co/datasets/dchitimalla1/raku-20250523)
313
+
314
+ ---
315
+
130
316
  ## Security Rules (165 total)
131
317
 
132
318
  ### By Language
package/index.js CHANGED
@@ -824,6 +824,235 @@ server.tool(
824
824
  }
825
825
  );
826
826
 
827
+ // ===========================================
828
+ // PACKAGE HALLUCINATION DETECTION
829
+ // ===========================================
830
+
831
+ // Load legitimate package lists into memory (hash sets for O(1) lookup)
832
+ const LEGITIMATE_PACKAGES = {
833
+ dart: new Set(),
834
+ perl: new Set(),
835
+ raku: new Set(),
836
+ npm: new Set(),
837
+ pypi: new Set()
838
+ };
839
+
840
+ // Package import patterns by ecosystem
841
+ const IMPORT_PATTERNS = {
842
+ dart: [
843
+ /import\s+['"]package:([^\/'"]+)/g,
844
+ /dependencies:\s*\n(?:\s+(\w+):\s*[\^~]?[\d.]+\n)+/g
845
+ ],
846
+ perl: [
847
+ /use\s+([\w:]+)/g,
848
+ /require\s+([\w:]+)/g
849
+ ],
850
+ raku: [
851
+ /use\s+([\w:]+)/g,
852
+ /need\s+([\w:]+)/g
853
+ ],
854
+ npm: [
855
+ /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
856
+ /from\s+['"]([^'"]+)['"]/g,
857
+ /import\s+['"]([^'"]+)['"]/g
858
+ ],
859
+ pypi: [
860
+ /^import\s+([\w]+)/gm,
861
+ /^from\s+([\w]+)/gm
862
+ ]
863
+ };
864
+
865
+ // Load package lists on startup
866
+ function loadPackageLists() {
867
+ const packagesDir = join(__dirname, 'packages');
868
+
869
+ for (const ecosystem of Object.keys(LEGITIMATE_PACKAGES)) {
870
+ const filePath = join(packagesDir, `${ecosystem}.txt`);
871
+ try {
872
+ if (existsSync(filePath)) {
873
+ const content = readFileSync(filePath, 'utf-8');
874
+ const packages = content.split('\n').filter(p => p.trim());
875
+ LEGITIMATE_PACKAGES[ecosystem] = new Set(packages);
876
+ console.error(`Loaded ${packages.length} ${ecosystem} packages`);
877
+ }
878
+ } catch (error) {
879
+ console.error(`Warning: Could not load ${ecosystem} packages: ${error.message}`);
880
+ }
881
+ }
882
+ }
883
+
884
+ // Extract package names from code
885
+ function extractPackages(code, ecosystem) {
886
+ const packages = new Set();
887
+ const patterns = IMPORT_PATTERNS[ecosystem] || [];
888
+
889
+ for (const pattern of patterns) {
890
+ const regex = new RegExp(pattern.source, pattern.flags);
891
+ let match;
892
+ while ((match = regex.exec(code)) !== null) {
893
+ const pkg = match[1];
894
+ if (pkg && !pkg.startsWith('.') && !pkg.startsWith('/')) {
895
+ // Normalize package name (handle scoped packages, subpaths)
896
+ const basePkg = pkg.split('/')[0].replace(/^@/, '');
897
+ packages.add(basePkg);
898
+ }
899
+ }
900
+ }
901
+
902
+ return Array.from(packages);
903
+ }
904
+
905
+ // Check if a package is hallucinated
906
+ function isHallucinated(packageName, ecosystem) {
907
+ const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
908
+ if (!legitPackages || legitPackages.size === 0) {
909
+ return { unknown: true, reason: `No package list loaded for ${ecosystem}` };
910
+ }
911
+ return { hallucinated: !legitPackages.has(packageName) };
912
+ }
913
+
914
+ // Register check_package tool
915
+ server.tool(
916
+ "check_package",
917
+ "Check if a package name is legitimate or potentially hallucinated (AI-invented)",
918
+ {
919
+ package_name: z.string().describe("The package name to verify"),
920
+ ecosystem: z.enum(["dart", "perl", "raku", "npm", "pypi"]).describe("The package ecosystem")
921
+ },
922
+ async ({ package_name, ecosystem }) => {
923
+ const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
924
+ const totalPackages = legitPackages?.size || 0;
925
+
926
+ if (totalPackages === 0) {
927
+ return {
928
+ content: [{
929
+ type: "text",
930
+ text: JSON.stringify({
931
+ package: package_name,
932
+ ecosystem,
933
+ status: "unknown",
934
+ reason: `No package list loaded for ${ecosystem}. Add packages/${ecosystem}.txt`,
935
+ suggestion: "Load package list or verify manually at the package registry"
936
+ }, null, 2)
937
+ }]
938
+ };
939
+ }
940
+
941
+ const exists = legitPackages.has(package_name);
942
+
943
+ return {
944
+ content: [{
945
+ type: "text",
946
+ text: JSON.stringify({
947
+ package: package_name,
948
+ ecosystem,
949
+ legitimate: exists,
950
+ hallucinated: !exists,
951
+ confidence: "high",
952
+ total_known_packages: totalPackages,
953
+ recommendation: exists
954
+ ? "Package exists in registry - safe to use"
955
+ : "⚠️ POTENTIAL HALLUCINATION - Package not found in registry. Verify before using!"
956
+ }, null, 2)
957
+ }]
958
+ };
959
+ }
960
+ );
961
+
962
+ // Register scan_packages tool
963
+ server.tool(
964
+ "scan_packages",
965
+ "Scan code for package imports and check for hallucinated (AI-invented) packages",
966
+ {
967
+ file_path: z.string().describe("Path to the file to scan"),
968
+ ecosystem: z.enum(["dart", "perl", "raku", "npm", "pypi"]).describe("The package ecosystem")
969
+ },
970
+ async ({ file_path, ecosystem }) => {
971
+ if (!existsSync(file_path)) {
972
+ return {
973
+ content: [{ type: "text", text: JSON.stringify({ error: "File not found" }) }]
974
+ };
975
+ }
976
+
977
+ const code = readFileSync(file_path, 'utf-8');
978
+ const packages = extractPackages(code, ecosystem);
979
+ const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
980
+ const totalKnown = legitPackages?.size || 0;
981
+
982
+ if (totalKnown === 0) {
983
+ return {
984
+ content: [{
985
+ type: "text",
986
+ text: JSON.stringify({
987
+ file: file_path,
988
+ ecosystem,
989
+ packages_found: packages,
990
+ status: "unknown",
991
+ reason: `No package list loaded for ${ecosystem}`
992
+ }, null, 2)
993
+ }]
994
+ };
995
+ }
996
+
997
+ const results = packages.map(pkg => ({
998
+ package: pkg,
999
+ legitimate: legitPackages.has(pkg),
1000
+ hallucinated: !legitPackages.has(pkg)
1001
+ }));
1002
+
1003
+ const hallucinated = results.filter(r => r.hallucinated);
1004
+ const legitimate = results.filter(r => r.legitimate);
1005
+
1006
+ return {
1007
+ content: [{
1008
+ type: "text",
1009
+ text: JSON.stringify({
1010
+ file: file_path,
1011
+ ecosystem,
1012
+ total_packages_found: packages.length,
1013
+ legitimate_count: legitimate.length,
1014
+ hallucinated_count: hallucinated.length,
1015
+ known_packages_in_registry: totalKnown,
1016
+ hallucinated_packages: hallucinated.map(r => r.package),
1017
+ legitimate_packages: legitimate.map(r => r.package),
1018
+ all_results: results,
1019
+ recommendation: hallucinated.length > 0
1020
+ ? `⚠️ Found ${hallucinated.length} potentially hallucinated package(s): ${hallucinated.map(r => r.package).join(', ')}`
1021
+ : "✅ All packages verified as legitimate"
1022
+ }, null, 2)
1023
+ }]
1024
+ };
1025
+ }
1026
+ );
1027
+
1028
+ // Register list_package_stats tool
1029
+ server.tool(
1030
+ "list_package_stats",
1031
+ "List statistics about loaded package lists for hallucination detection",
1032
+ {},
1033
+ async () => {
1034
+ const stats = Object.entries(LEGITIMATE_PACKAGES).map(([ecosystem, packages]) => ({
1035
+ ecosystem,
1036
+ packages_loaded: packages.size,
1037
+ status: packages.size > 0 ? "ready" : "not loaded"
1038
+ }));
1039
+
1040
+ return {
1041
+ content: [{
1042
+ type: "text",
1043
+ text: JSON.stringify({
1044
+ package_lists: stats,
1045
+ total_packages: stats.reduce((sum, s) => sum + s.packages_loaded, 0),
1046
+ usage: "Use check_package or scan_packages to detect hallucinated packages"
1047
+ }, null, 2)
1048
+ }]
1049
+ };
1050
+ }
1051
+ );
1052
+
1053
+ // Load package lists on module initialization
1054
+ loadPackageLists();
1055
+
827
1056
  // Start the server with stdio transport
828
1057
  async function main() {
829
1058
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-security-scanner-mcp",
3
- "version": "1.0.2",
4
- "description": "MCP server for security vulnerability scanning - detects SQL injection, XSS, command injection, hardcoded secrets, and more",
3
+ "version": "1.1.1",
4
+ "description": "MCP server for security scanning & package hallucination detection - SQL injection, XSS, secrets, and AI-invented package detection",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -21,7 +21,10 @@
21
21
  "code-analysis",
22
22
  "sql-injection",
23
23
  "xss",
24
- "secrets-detection"
24
+ "secrets-detection",
25
+ "hallucination-detection",
26
+ "package-verification",
27
+ "supply-chain-security"
25
28
  ],
26
29
  "author": "",
27
30
  "license": "MIT",
@@ -43,6 +46,7 @@
43
46
  "files": [
44
47
  "index.js",
45
48
  "analyzer.py",
46
- "rules/**"
49
+ "rules/**",
50
+ "packages/**"
47
51
  ]
48
52
  }