agent-security-scanner-mcp 1.4.3 → 1.4.5

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
@@ -2,16 +2,14 @@
2
2
 
3
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
- **275+ Semgrep-aligned security rules | 105 auto-fix templates | 4.3M+ packages indexed | AI Agent prompt security**
5
+ **275+ Semgrep-aligned security rules | 105 auto-fix templates | 1M+ packages indexed | AI Agent prompt security**
6
6
 
7
- ## What's New in v1.4.3
7
+ ## What's New in v1.4.5
8
8
 
9
- - **72% smaller package size** - Bloom Filter for npm reduces package from 84MB to 23MB
10
- - **4.3M+ packages indexed** - Massively expanded hallucination detection database
11
- - **7 ecosystems supported** - npm, PyPI, RubyGems, crates.io, pub.dev, CPAN, raku.land
12
- - **Python & JavaScript support** - Now detects hallucinated npm and PyPI packages
13
- - **Ruby & Rust support** - Coverage for RubyGems and crates.io
14
- - **garak-llm datasets** - Using official package snapshots from Hugging Face
9
+ - **92% smaller package** - Only 2.7 MB (down from 84 MB)
10
+ - **6 ecosystems included** - PyPI, RubyGems, crates.io, pub.dev, CPAN, raku.land
11
+ - **npm available separately** - Use `agent-security-scanner-mcp-full` for npm support (adds 7.6 MB)
12
+ - **Bloom Filters** - Efficient storage for large package lists
15
13
 
16
14
  ## What's New in v1.3.0
17
15
 
@@ -40,10 +38,22 @@ A powerful MCP (Model Context Protocol) server for real-time security vulnerabil
40
38
 
41
39
  ## Installation
42
40
 
41
+ ### Default Package (Lightweight - 2.7 MB)
42
+
43
43
  ```bash
44
44
  npm install -g agent-security-scanner-mcp
45
45
  ```
46
46
 
47
+ Includes hallucination detection for: **PyPI, RubyGems, crates.io, pub.dev, CPAN, raku.land** (1M+ packages)
48
+
49
+ ### Full Package (With npm - 8.7 MB)
50
+
51
+ If you need **npm/JavaScript hallucination detection** (3.3M packages):
52
+
53
+ ```bash
54
+ npm install -g agent-security-scanner-mcp-full
55
+ ```
56
+
47
57
  Or run directly with npx:
48
58
 
49
59
  ```bash
package/index.js CHANGED
@@ -941,14 +941,25 @@ const LEGITIMATE_PACKAGES = {
941
941
  dart: new Set(),
942
942
  perl: new Set(),
943
943
  raku: new Set(),
944
- npm: null, // Uses Bloom Filter instead of Set
945
- pypi: new Set(),
946
- rubygems: new Set(),
944
+ npm: null, // Uses Bloom Filter
945
+ pypi: null, // Uses Bloom Filter
946
+ rubygems: null, // Uses Bloom Filter
947
947
  crates: new Set()
948
948
  };
949
949
 
950
- // Bloom Filter for npm (handles 3.3M+ packages efficiently)
951
- let npmBloomFilter = null;
950
+ // Bloom Filters for large ecosystems (npm, pypi, rubygems)
951
+ const BLOOM_FILTERS = {
952
+ npm: null,
953
+ pypi: null,
954
+ rubygems: null
955
+ };
956
+
957
+ // Package counts for bloom filter ecosystems (filter doesn't store count)
958
+ const BLOOM_COUNTS = {
959
+ npm: 3329177,
960
+ pypi: 554762,
961
+ rubygems: 180693
962
+ };
952
963
 
953
964
  // Package import patterns by ecosystem
954
965
  const IMPORT_PATTERNS = {
@@ -989,21 +1000,23 @@ const IMPORT_PATTERNS = {
989
1000
  function loadPackageLists() {
990
1001
  const packagesDir = join(__dirname, 'packages');
991
1002
 
992
- // Load npm packages using Bloom Filter (88% smaller than txt file)
993
- try {
994
- const npmBloomPath = join(packagesDir, 'npm-bloom.json');
995
- if (existsSync(npmBloomPath)) {
996
- const bloomData = JSON.parse(readFileSync(npmBloomPath, 'utf-8'));
997
- npmBloomFilter = BloomFilter.fromJSON(bloomData);
998
- console.error(`Loaded npm Bloom Filter (3.3M+ packages, 0.1% false positive rate)`);
1003
+ // Load Bloom Filter ecosystems (npm, pypi, rubygems)
1004
+ for (const ecosystem of Object.keys(BLOOM_FILTERS)) {
1005
+ try {
1006
+ const bloomPath = join(packagesDir, `${ecosystem}-bloom.json`);
1007
+ if (existsSync(bloomPath)) {
1008
+ const bloomData = JSON.parse(readFileSync(bloomPath, 'utf-8'));
1009
+ BLOOM_FILTERS[ecosystem] = BloomFilter.fromJSON(bloomData);
1010
+ console.error(`Loaded ${ecosystem} Bloom Filter (${BLOOM_COUNTS[ecosystem].toLocaleString()} packages)`);
1011
+ }
1012
+ } catch (error) {
1013
+ console.error(`Warning: Could not load ${ecosystem} Bloom Filter: ${error.message}`);
999
1014
  }
1000
- } catch (error) {
1001
- console.error(`Warning: Could not load npm Bloom Filter: ${error.message}`);
1002
1015
  }
1003
1016
 
1004
- // Load other ecosystems using regular Set
1017
+ // Load other ecosystems using regular Set (smaller lists)
1005
1018
  for (const ecosystem of Object.keys(LEGITIMATE_PACKAGES)) {
1006
- if (ecosystem === 'npm') continue; // npm uses Bloom Filter
1019
+ if (BLOOM_FILTERS.hasOwnProperty(ecosystem)) continue; // Uses Bloom Filter
1007
1020
 
1008
1021
  const filePath = join(packagesDir, `${ecosystem}.txt`);
1009
1022
  try {
@@ -1017,6 +1030,11 @@ function loadPackageLists() {
1017
1030
  console.error(`Warning: Could not load ${ecosystem} packages: ${error.message}`);
1018
1031
  }
1019
1032
  }
1033
+
1034
+ // Note about npm if not loaded
1035
+ if (!BLOOM_FILTERS.npm) {
1036
+ console.error(`npm: not included (use agent-security-scanner-mcp-full for npm support)`);
1037
+ }
1020
1038
  }
1021
1039
 
1022
1040
  // Extract package names from code
@@ -1042,27 +1060,33 @@ function extractPackages(code, ecosystem) {
1042
1060
 
1043
1061
  // Check if a package exists in the package list
1044
1062
  function packageExists(packageName, ecosystem) {
1045
- if (ecosystem === 'npm') {
1046
- return npmBloomFilter ? npmBloomFilter.has(packageName) : false;
1063
+ // Bloom Filter ecosystems
1064
+ if (BLOOM_FILTERS.hasOwnProperty(ecosystem)) {
1065
+ return BLOOM_FILTERS[ecosystem] ? BLOOM_FILTERS[ecosystem].has(packageName) : false;
1047
1066
  }
1067
+ // Set-based ecosystems
1048
1068
  const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
1049
1069
  return legitPackages ? legitPackages.has(packageName) : false;
1050
1070
  }
1051
1071
 
1052
1072
  // Get package count for an ecosystem
1053
1073
  function getPackageCount(ecosystem) {
1054
- if (ecosystem === 'npm') {
1055
- return npmBloomFilter ? 3329177 : 0; // Bloom filter doesn't store count
1074
+ // Bloom Filter ecosystems
1075
+ if (BLOOM_FILTERS.hasOwnProperty(ecosystem)) {
1076
+ return BLOOM_FILTERS[ecosystem] ? BLOOM_COUNTS[ecosystem] : 0;
1056
1077
  }
1078
+ // Set-based ecosystems
1057
1079
  const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
1058
1080
  return legitPackages ? legitPackages.size : 0;
1059
1081
  }
1060
1082
 
1061
1083
  // Check if ecosystem is loaded
1062
1084
  function isEcosystemLoaded(ecosystem) {
1063
- if (ecosystem === 'npm') {
1064
- return npmBloomFilter !== null;
1085
+ // Bloom Filter ecosystems
1086
+ if (BLOOM_FILTERS.hasOwnProperty(ecosystem)) {
1087
+ return BLOOM_FILTERS[ecosystem] !== null;
1065
1088
  }
1089
+ // Set-based ecosystems
1066
1090
  const legitPackages = LEGITIMATE_PACKAGES[ecosystem];
1067
1091
  return legitPackages && legitPackages.size > 0;
1068
1092
  }
@@ -1084,6 +1108,22 @@ server.tool(
1084
1108
  ecosystem: z.enum(["dart", "perl", "raku", "npm", "pypi", "rubygems", "crates"]).describe("The package ecosystem (dart=pub.dev, perl=CPAN, raku=raku.land, npm=npmjs, pypi=PyPI, rubygems=RubyGems, crates=crates.io)")
1085
1109
  },
1086
1110
  async ({ package_name, ecosystem }) => {
1111
+ // Check if npm is requested but not available
1112
+ if (ecosystem === 'npm' && !BLOOM_FILTERS.npm) {
1113
+ return {
1114
+ content: [{
1115
+ type: "text",
1116
+ text: JSON.stringify({
1117
+ package: package_name,
1118
+ ecosystem,
1119
+ status: "unavailable",
1120
+ reason: "npm hallucination detection not included in default package (saves 7.6 MB)",
1121
+ suggestion: "Use 'agent-security-scanner-mcp-full' for npm support, or verify manually at npmjs.com"
1122
+ }, null, 2)
1123
+ }]
1124
+ };
1125
+ }
1126
+
1087
1127
  const totalPackages = getPackageCount(ecosystem);
1088
1128
 
1089
1129
  if (!isEcosystemLoaded(ecosystem)) {
@@ -1094,8 +1134,8 @@ server.tool(
1094
1134
  package: package_name,
1095
1135
  ecosystem,
1096
1136
  status: "unknown",
1097
- reason: `No package list loaded for ${ecosystem}. Add packages/${ecosystem}.txt`,
1098
- suggestion: "Load package list or verify manually at the package registry"
1137
+ reason: `No package list loaded for ${ecosystem}`,
1138
+ suggestion: "Verify manually at the package registry"
1099
1139
  }, null, 2)
1100
1140
  }]
1101
1141
  };
@@ -1137,6 +1177,22 @@ server.tool(
1137
1177
  };
1138
1178
  }
1139
1179
 
1180
+ // Check if npm is requested but not available
1181
+ if (ecosystem === 'npm' && !BLOOM_FILTERS.npm) {
1182
+ return {
1183
+ content: [{
1184
+ type: "text",
1185
+ text: JSON.stringify({
1186
+ file: file_path,
1187
+ ecosystem,
1188
+ status: "unavailable",
1189
+ reason: "npm hallucination detection not included in default package (saves 7.6 MB)",
1190
+ suggestion: "Use 'agent-security-scanner-mcp-full' for npm support, or verify manually at npmjs.com"
1191
+ }, null, 2)
1192
+ }]
1193
+ };
1194
+ }
1195
+
1140
1196
  const code = readFileSync(file_path, 'utf-8');
1141
1197
  const packages = extractPackages(code, ecosystem);
1142
1198
  const totalKnown = getPackageCount(ecosystem);
@@ -1194,12 +1250,23 @@ server.tool(
1194
1250
  {},
1195
1251
  async () => {
1196
1252
  const ecosystems = ['npm', 'pypi', 'rubygems', 'crates', 'dart', 'perl', 'raku'];
1197
- const stats = ecosystems.map(ecosystem => ({
1198
- ecosystem,
1199
- packages_loaded: getPackageCount(ecosystem),
1200
- status: isEcosystemLoaded(ecosystem) ? "ready" : "not loaded",
1201
- storage: ecosystem === 'npm' ? "bloom filter" : "hash set"
1202
- }));
1253
+ const stats = ecosystems.map(ecosystem => {
1254
+ const loaded = isEcosystemLoaded(ecosystem);
1255
+ let status = loaded ? "ready" : "not loaded";
1256
+ let storage = BLOOM_FILTERS.hasOwnProperty(ecosystem) ? "bloom filter" : "hash set";
1257
+
1258
+ // npm is not included in default package
1259
+ if (ecosystem === 'npm' && !loaded) {
1260
+ status = "not included (use -full package)";
1261
+ }
1262
+
1263
+ return {
1264
+ ecosystem,
1265
+ packages_loaded: loaded ? getPackageCount(ecosystem) : 0,
1266
+ status,
1267
+ storage
1268
+ };
1269
+ });
1203
1270
 
1204
1271
  return {
1205
1272
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-security-scanner-mcp",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "MCP server for security scanning, AI agent prompt security & package hallucination detection. Works with Claude Desktop, Claude Code, OpenCode, Kilo Code. Detects SQL injection, XSS, secrets, prompt attacks, and AI-invented packages.",
5
5
  "main": "index.js",
6
6
  "type": "module",