@bryan-thompson/inspector-assessment-cli 1.24.2 → 1.25.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.
@@ -32,6 +32,7 @@ import { compareAssessments } from "../../client/lib/lib/assessmentDiffer.js";
32
32
  import { formatDiffAsMarkdown } from "../../client/lib/lib/reportFormatters/DiffReportFormatter.js";
33
33
  import { AssessmentStateManager } from "./assessmentState.js";
34
34
  import { emitServerConnected, emitToolDiscovered, emitToolsDiscoveryComplete, emitAssessmentComplete, emitTestBatch, emitVulnerabilityFound, emitAnnotationMissing, emitAnnotationMisaligned, emitAnnotationReviewRecommended, emitAnnotationAligned, emitModulesConfigured, } from "./lib/jsonl-events.js";
35
+ import { ASSESSMENT_PROFILES, isValidProfileName, getProfileModules, resolveModuleNames, modulesToLegacyConfig, getProfileHelpText, } from "./profiles.js";
35
36
  // Valid module names derived from ASSESSMENT_CATEGORY_METADATA
36
37
  const VALID_MODULE_NAMES = Object.keys(ASSESSMENT_CATEGORY_METADATA);
37
38
  /**
@@ -342,28 +343,45 @@ function buildConfig(options) {
342
343
  enableSourceCodeAnalysis: Boolean(options.sourceCodePath),
343
344
  };
344
345
  if (options.fullAssessment !== false) {
345
- // Derive module config from ASSESSMENT_CATEGORY_METADATA (single source of truth)
346
- const allModules = getAllModulesConfig({
347
- sourceCodePath: Boolean(options.sourceCodePath),
348
- skipTemporal: options.skipTemporal,
349
- });
350
- // Apply --only-modules filter (whitelist mode)
351
- if (options.onlyModules?.length) {
352
- for (const key of Object.keys(allModules)) {
353
- // Disable all modules except those in the whitelist
354
- allModules[key] = options.onlyModules.includes(key);
355
- }
346
+ // Priority: --profile > --only-modules > --skip-modules > default (all)
347
+ if (options.profile) {
348
+ // Use profile-based module selection
349
+ const profileModules = getProfileModules(options.profile, {
350
+ hasSourceCode: Boolean(options.sourceCodePath),
351
+ skipTemporal: options.skipTemporal,
352
+ });
353
+ // Convert new-style module list to legacy config format
354
+ // (until orchestrator is updated to use new naming)
355
+ config.assessmentCategories = modulesToLegacyConfig(profileModules);
356
356
  }
357
- // Apply --skip-modules filter (blacklist mode)
358
- if (options.skipModules?.length) {
359
- for (const module of options.skipModules) {
360
- if (module in allModules) {
361
- allModules[module] = false;
357
+ else {
358
+ // Derive module config from ASSESSMENT_CATEGORY_METADATA (single source of truth)
359
+ const allModules = getAllModulesConfig({
360
+ sourceCodePath: Boolean(options.sourceCodePath),
361
+ skipTemporal: options.skipTemporal,
362
+ });
363
+ // Apply --only-modules filter (whitelist mode)
364
+ if (options.onlyModules?.length) {
365
+ // Resolve any deprecated module names
366
+ const resolved = resolveModuleNames(options.onlyModules);
367
+ for (const key of Object.keys(allModules)) {
368
+ // Disable all modules except those in the whitelist
369
+ allModules[key] = resolved.includes(key);
362
370
  }
363
371
  }
372
+ // Apply --skip-modules filter (blacklist mode)
373
+ if (options.skipModules?.length) {
374
+ // Resolve any deprecated module names
375
+ const resolved = resolveModuleNames(options.skipModules);
376
+ for (const module of resolved) {
377
+ if (module in allModules) {
378
+ allModules[module] = false;
379
+ }
380
+ }
381
+ }
382
+ config.assessmentCategories =
383
+ allModules;
364
384
  }
365
- config.assessmentCategories =
366
- allModules;
367
385
  }
368
386
  // Temporal/rug pull detection configuration
369
387
  if (options.temporalInvocations) {
@@ -922,6 +940,25 @@ function parseArgs() {
922
940
  case "--skip-temporal":
923
941
  options.skipTemporal = true;
924
942
  break;
943
+ case "--profile": {
944
+ const profileValue = args[++i];
945
+ if (!profileValue) {
946
+ console.error("Error: --profile requires a profile name");
947
+ console.error(`Valid profiles: ${Object.keys(ASSESSMENT_PROFILES).join(", ")}`);
948
+ setTimeout(() => process.exit(1), 10);
949
+ options.helpRequested = true;
950
+ return options;
951
+ }
952
+ if (!isValidProfileName(profileValue)) {
953
+ console.error(`Error: Invalid profile name: ${profileValue}`);
954
+ console.error(`Valid profiles: ${Object.keys(ASSESSMENT_PROFILES).join(", ")}`);
955
+ setTimeout(() => process.exit(1), 10);
956
+ options.helpRequested = true;
957
+ return options;
958
+ }
959
+ options.profile = profileValue;
960
+ break;
961
+ }
925
962
  case "--skip-modules": {
926
963
  const skipValue = args[++i];
927
964
  if (!skipValue) {
@@ -972,7 +1009,13 @@ function parseArgs() {
972
1009
  }
973
1010
  }
974
1011
  }
975
- // Validate mutual exclusivity of --skip-modules and --only-modules
1012
+ // Validate mutual exclusivity of --profile, --skip-modules, and --only-modules
1013
+ if (options.profile && (options.skipModules?.length || options.onlyModules?.length)) {
1014
+ console.error("Error: --profile cannot be used with --skip-modules or --only-modules");
1015
+ setTimeout(() => process.exit(1), 10);
1016
+ options.helpRequested = true;
1017
+ return options;
1018
+ }
976
1019
  if (options.skipModules?.length && options.onlyModules?.length) {
977
1020
  console.error("Error: --skip-modules and --only-modules are mutually exclusive");
978
1021
  setTimeout(() => process.exit(1), 10);
@@ -995,7 +1038,7 @@ function printHelp() {
995
1038
  console.log(`
996
1039
  Usage: mcp-assess-full [options] [server-name]
997
1040
 
998
- Run comprehensive MCP server assessment with all 17 assessor modules.
1041
+ Run comprehensive MCP server assessment with 16 assessor modules organized in 4 tiers.
999
1042
 
1000
1043
  Options:
1001
1044
  --server, -s <name> Server name (required, or pass as first positional arg)
@@ -1012,6 +1055,7 @@ Options:
1012
1055
  --no-resume Force fresh start, clear any existing state
1013
1056
  --claude-enabled Enable Claude Code integration for intelligent analysis
1014
1057
  --full Enable all assessment modules (default)
1058
+ --profile <name> Use predefined module profile (quick, security, compliance, full)
1015
1059
  --temporal-invocations <n> Number of invocations per tool for rug pull detection (default: 25)
1016
1060
  --skip-temporal Skip temporal/rug pull testing (faster assessment)
1017
1061
  --skip-modules <list> Skip specific modules (comma-separated)
@@ -1023,47 +1067,65 @@ Options:
1023
1067
  Also supports LOG_LEVEL environment variable
1024
1068
  --help, -h Show this help message
1025
1069
 
1070
+ ${getProfileHelpText()}
1026
1071
  Module Selection:
1027
- --skip-modules and --only-modules are mutually exclusive.
1028
- Use --skip-modules for faster runs by disabling expensive modules.
1072
+ --profile, --skip-modules, and --only-modules are mutually exclusive.
1073
+ Use --profile for common assessment scenarios.
1074
+ Use --skip-modules for custom runs by disabling expensive modules.
1029
1075
  Use --only-modules to focus on specific areas (e.g., tool annotation PRs).
1030
1076
 
1031
- Valid module names:
1032
- functionality, security, documentation, errorHandling, usability,
1033
- mcpSpecCompliance, aupCompliance, toolAnnotations, prohibitedLibraries,
1034
- externalAPIScanner, authentication, temporal, resources, prompts,
1035
- crossCapability, manifestValidation, portability
1077
+ Valid module names (new naming):
1078
+ functionality, security, errorHandling, protocolCompliance, aupCompliance,
1079
+ toolAnnotations, prohibitedLibraries, manifestValidation, authentication,
1080
+ temporal, resources, prompts, crossCapability, developerExperience,
1081
+ portability, externalAPIScanner
1082
+
1083
+ Legacy module names (deprecated, will map to new names):
1084
+ documentation -> developerExperience
1085
+ usability -> developerExperience
1086
+ mcpSpecCompliance -> protocolCompliance
1087
+ protocolConformance -> protocolCompliance
1088
+
1089
+ Module Tiers (16 total):
1090
+ Tier 1 - Core Security (Always Run):
1091
+ • Functionality - Tests all tools work correctly
1092
+ • Security - Prompt injection & vulnerability testing
1093
+ • Error Handling - Validates error responses
1094
+ • Protocol Compliance - MCP protocol + JSON-RPC validation
1095
+ • AUP Compliance - Acceptable Use Policy checks
1096
+ • Temporal - Rug pull/temporal behavior change detection
1036
1097
 
1037
- Assessment Modules (17 total):
1038
- Functionality - Tests all tools work correctly
1039
- Security - Prompt injection & vulnerability testing
1040
- Documentation - README completeness checks
1041
- Error Handling - Validates error responses
1042
- • Usability - Input validation & UX
1043
- MCP Spec - Protocol compliance
1044
- AUP Compliance - Acceptable Use Policy checks
1045
- Tool Annotations - readOnlyHint/destructiveHint validation
1046
- Prohibited Libs - Dependency security checks
1047
- • External API - External service detection
1048
- Authentication - OAuth/auth evaluation
1049
- Temporal - Rug pull/temporal behavior change detection
1050
- Resources - Resource capability assessment
1051
- Prompts - Prompt capability assessment
1052
- • Cross-Capability - Chained vulnerability detection
1053
- • Manifest - MCPB manifest.json validation (optional)
1054
- • Portability - Cross-platform compatibility (optional)
1098
+ Tier 2 - Compliance (MCP Directory):
1099
+ Tool Annotations - readOnlyHint/destructiveHint validation
1100
+ Prohibited Libs - Dependency security checks
1101
+ Manifest - MCPB manifest.json validation
1102
+ Authentication - OAuth/auth evaluation
1103
+
1104
+ Tier 3 - Capability-Based (Conditional):
1105
+ Resources - Resource capability assessment
1106
+ Prompts - Prompt capability assessment
1107
+ Cross-Capability - Chained vulnerability detection
1108
+
1109
+ Tier 4 - Extended (Optional):
1110
+ Developer Experience - Documentation + usability assessment
1111
+ Portability - Cross-platform compatibility
1112
+ External API - External service detection
1055
1113
 
1056
1114
  Examples:
1057
- mcp-assess-full my-server
1058
- mcp-assess-full --server broken-mcp --claude-enabled
1059
- mcp-assess-full --server my-server --source ./my-server --output ./results.json
1060
- mcp-assess-full --server my-server --format markdown --include-policy
1061
- mcp-assess-full --server my-server --compare ./baseline.json
1062
- mcp-assess-full --server my-server --compare ./baseline.json --diff-only --format markdown
1115
+ # Profile-based (recommended):
1116
+ mcp-assess-full my-server --profile quick # CI/CD fast check (~30s)
1117
+ mcp-assess-full my-server --profile security # Security audit (~2-3min)
1118
+ mcp-assess-full my-server --profile compliance # Directory submission (~5min)
1119
+ mcp-assess-full my-server --profile full # Comprehensive audit (~10-15min)
1063
1120
 
1064
- # Module selection examples:
1065
- mcp-assess-full my-server --skip-modules security,aupCompliance # Fast CI run
1121
+ # Custom module selection:
1122
+ mcp-assess-full my-server --skip-modules temporal,resources # Skip expensive modules
1066
1123
  mcp-assess-full my-server --only-modules functionality,toolAnnotations # Annotation PR review
1124
+
1125
+ # Advanced options:
1126
+ mcp-assess-full --server my-server --source ./my-server --output ./results.json
1127
+ mcp-assess-full --server my-server --format markdown --include-policy
1128
+ mcp-assess-full --server my-server --compare ./baseline.json --diff-only
1067
1129
  `);
1068
1130
  }
1069
1131
  /**
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Assessment Profiles
3
+ *
4
+ * Pre-configured module sets for common assessment scenarios.
5
+ * Profiles map to the 4-tier module organization:
6
+ *
7
+ * Tier 1: Core Security (Always Run)
8
+ * - functionality, security, temporal, errorHandling, protocolCompliance, aupCompliance
9
+ *
10
+ * Tier 2: Compliance (MCP Directory)
11
+ * - toolAnnotations, prohibitedLibraries, manifestValidation, authentication
12
+ *
13
+ * Tier 3: Capability-Based (Conditional)
14
+ * - resources, prompts, crossCapability
15
+ *
16
+ * Tier 4: Extended (Optional)
17
+ * - developerExperience, portability, externalAPIScanner
18
+ *
19
+ * @module cli/profiles
20
+ */
21
+ /**
22
+ * Module alias mappings for backward compatibility.
23
+ * Maps deprecated module names to their replacements.
24
+ */
25
+ export const MODULE_ALIASES = {
26
+ // Protocol compliance merge (MCPSpec + ProtocolConformance → ProtocolCompliance)
27
+ mcpSpecCompliance: "protocolCompliance",
28
+ protocolConformance: "protocolCompliance",
29
+ // Developer experience merge (Documentation + Usability → DeveloperExperience)
30
+ documentation: "developerExperience",
31
+ usability: "developerExperience",
32
+ };
33
+ /**
34
+ * Deprecated module names that trigger a warning when used.
35
+ */
36
+ export const DEPRECATED_MODULES = new Set(Object.keys(MODULE_ALIASES));
37
+ /**
38
+ * Tier 1: Core Security modules
39
+ * Essential for any MCP server assessment - security-focused
40
+ */
41
+ export const TIER_1_CORE_SECURITY = [
42
+ "functionality",
43
+ "security",
44
+ "temporal",
45
+ "errorHandling",
46
+ "protocolCompliance",
47
+ "aupCompliance",
48
+ ];
49
+ /**
50
+ * Tier 2: Compliance modules
51
+ * Required for MCP Directory submission compliance
52
+ */
53
+ export const TIER_2_COMPLIANCE = [
54
+ "toolAnnotations",
55
+ "prohibitedLibraries",
56
+ "manifestValidation",
57
+ "authentication",
58
+ ];
59
+ /**
60
+ * Tier 3: Capability-Based modules
61
+ * Only run when server has corresponding capabilities
62
+ */
63
+ export const TIER_3_CAPABILITY = [
64
+ "resources",
65
+ "prompts",
66
+ "crossCapability",
67
+ ];
68
+ /**
69
+ * Tier 4: Extended modules
70
+ * Optional assessments for comprehensive audits
71
+ */
72
+ export const TIER_4_EXTENDED = [
73
+ "developerExperience",
74
+ "portability",
75
+ "externalAPIScanner",
76
+ ];
77
+ /**
78
+ * All available modules (new naming)
79
+ */
80
+ export const ALL_MODULES = [
81
+ ...TIER_1_CORE_SECURITY,
82
+ ...TIER_2_COMPLIANCE,
83
+ ...TIER_3_CAPABILITY,
84
+ ...TIER_4_EXTENDED,
85
+ ];
86
+ /**
87
+ * Assessment profile definitions
88
+ * Each profile includes a specific set of modules optimized for the use case.
89
+ */
90
+ export const ASSESSMENT_PROFILES = {
91
+ /**
92
+ * Quick profile: Minimal testing for fast CI/CD checks
93
+ * Use when: Pre-commit hooks, quick validation
94
+ * Time: ~30 seconds
95
+ */
96
+ quick: ["functionality", "security"],
97
+ /**
98
+ * Security profile: Core security modules (Tier 1)
99
+ * Use when: Security-focused audits, vulnerability scanning
100
+ * Time: ~2-3 minutes
101
+ */
102
+ security: [...TIER_1_CORE_SECURITY],
103
+ /**
104
+ * Compliance profile: Security + Directory compliance (Tier 1 + 2)
105
+ * Use when: Pre-submission validation for MCP Directory
106
+ * Time: ~5 minutes
107
+ */
108
+ compliance: [...TIER_1_CORE_SECURITY, ...TIER_2_COMPLIANCE],
109
+ /**
110
+ * Full profile: All modules (Tier 1 + 2 + 3 + 4)
111
+ * Use when: Comprehensive audits, initial server review
112
+ * Time: ~10-15 minutes
113
+ */
114
+ full: [
115
+ ...TIER_1_CORE_SECURITY,
116
+ ...TIER_2_COMPLIANCE,
117
+ ...TIER_3_CAPABILITY,
118
+ ...TIER_4_EXTENDED,
119
+ ],
120
+ };
121
+ export const PROFILE_METADATA = {
122
+ quick: {
123
+ description: "Fast validation (functionality + security only)",
124
+ estimatedTime: "~30 seconds",
125
+ moduleCount: ASSESSMENT_PROFILES.quick.length,
126
+ tiers: ["Tier 1 (partial)"],
127
+ },
128
+ security: {
129
+ description: "Core security modules for vulnerability scanning",
130
+ estimatedTime: "~2-3 minutes",
131
+ moduleCount: ASSESSMENT_PROFILES.security.length,
132
+ tiers: ["Tier 1 (Core Security)"],
133
+ },
134
+ compliance: {
135
+ description: "Security + MCP Directory compliance validation",
136
+ estimatedTime: "~5 minutes",
137
+ moduleCount: ASSESSMENT_PROFILES.compliance.length,
138
+ tiers: ["Tier 1 (Core Security)", "Tier 2 (Compliance)"],
139
+ },
140
+ full: {
141
+ description: "Comprehensive audit with all assessment modules",
142
+ estimatedTime: "~10-15 minutes",
143
+ moduleCount: ASSESSMENT_PROFILES.full.length,
144
+ tiers: [
145
+ "Tier 1 (Core Security)",
146
+ "Tier 2 (Compliance)",
147
+ "Tier 3 (Capability)",
148
+ "Tier 4 (Extended)",
149
+ ],
150
+ },
151
+ };
152
+ /**
153
+ * Resolve module names, applying aliases for deprecated names.
154
+ * Emits warnings for deprecated module usage.
155
+ *
156
+ * @param modules - Array of module names (may include deprecated names)
157
+ * @param warn - If true, emit console warnings for deprecated names
158
+ * @returns Array of resolved module names (with aliases applied)
159
+ */
160
+ export function resolveModuleNames(modules, warn = true) {
161
+ const resolved = new Set();
162
+ for (const module of modules) {
163
+ if (DEPRECATED_MODULES.has(module)) {
164
+ const replacement = MODULE_ALIASES[module];
165
+ if (warn) {
166
+ console.warn(`Warning: Module '${module}' is deprecated, using '${replacement}' instead`);
167
+ }
168
+ resolved.add(replacement);
169
+ }
170
+ else {
171
+ resolved.add(module);
172
+ }
173
+ }
174
+ return Array.from(resolved);
175
+ }
176
+ /**
177
+ * Get modules for a profile, with optional source code awareness.
178
+ *
179
+ * @param profileName - Profile to get modules for
180
+ * @param options.hasSourceCode - If true, includes source-dependent modules
181
+ * @param options.skipTemporal - If true, excludes temporal module
182
+ * @returns Array of module names to run
183
+ */
184
+ export function getProfileModules(profileName, options = {}) {
185
+ let modules = [...ASSESSMENT_PROFILES[profileName]];
186
+ // Filter out temporal if requested
187
+ if (options.skipTemporal) {
188
+ modules = modules.filter((m) => m !== "temporal");
189
+ }
190
+ // externalAPIScanner requires source code
191
+ if (!options.hasSourceCode) {
192
+ modules = modules.filter((m) => m !== "externalAPIScanner");
193
+ }
194
+ // prohibitedLibraries is most effective with source code
195
+ // (still runs but with limited capability)
196
+ return modules;
197
+ }
198
+ /**
199
+ * Validate a profile name.
200
+ *
201
+ * @param name - Profile name to validate
202
+ * @returns True if valid profile name
203
+ */
204
+ export function isValidProfileName(name) {
205
+ return name in ASSESSMENT_PROFILES;
206
+ }
207
+ /**
208
+ * Get help text for profiles.
209
+ */
210
+ export function getProfileHelpText() {
211
+ const lines = ["Assessment Profiles:", ""];
212
+ for (const [name, metadata] of Object.entries(PROFILE_METADATA)) {
213
+ lines.push(` ${name.padEnd(12)} ${metadata.description}`);
214
+ lines.push(` Modules: ${metadata.moduleCount}, Time: ${metadata.estimatedTime}`);
215
+ lines.push(` Tiers: ${metadata.tiers.join(", ")}`);
216
+ lines.push("");
217
+ }
218
+ return lines.join("\n");
219
+ }
220
+ /**
221
+ * Map old module config keys to new profile-based module list.
222
+ * Used for backward compatibility with existing configs.
223
+ *
224
+ * @param oldConfig - Old-style assessmentCategories object
225
+ * @returns Array of enabled module names (new naming)
226
+ */
227
+ export function mapLegacyConfigToModules(oldConfig) {
228
+ const enabled = [];
229
+ for (const [key, value] of Object.entries(oldConfig)) {
230
+ if (value === true) {
231
+ // Apply alias resolution for deprecated names
232
+ const resolved = MODULE_ALIASES[key] || key;
233
+ if (!enabled.includes(resolved)) {
234
+ enabled.push(resolved);
235
+ }
236
+ }
237
+ }
238
+ return enabled;
239
+ }
240
+ /**
241
+ * Convert new module list to old-style config object.
242
+ * Used for backward compatibility with existing orchestrator.
243
+ *
244
+ * @param modules - Array of module names (new naming)
245
+ * @returns Old-style assessmentCategories object
246
+ */
247
+ export function modulesToLegacyConfig(modules) {
248
+ // Start with all modules disabled
249
+ const config = {
250
+ functionality: false,
251
+ security: false,
252
+ documentation: false,
253
+ errorHandling: false,
254
+ usability: false,
255
+ mcpSpecCompliance: false,
256
+ aupCompliance: false,
257
+ toolAnnotations: false,
258
+ prohibitedLibraries: false,
259
+ manifestValidation: false,
260
+ portability: false,
261
+ externalAPIScanner: false,
262
+ authentication: false,
263
+ temporal: false,
264
+ resources: false,
265
+ prompts: false,
266
+ crossCapability: false,
267
+ protocolConformance: false,
268
+ };
269
+ // Enable requested modules, mapping new names to old where needed
270
+ for (const module of modules) {
271
+ if (module === "protocolCompliance") {
272
+ // Map to both old modules for backward compat until orchestrator updated
273
+ config.mcpSpecCompliance = true;
274
+ config.protocolConformance = true;
275
+ }
276
+ else if (module === "developerExperience") {
277
+ // Map to both old modules for backward compat until orchestrator updated
278
+ config.documentation = true;
279
+ config.usability = true;
280
+ }
281
+ else if (module in config) {
282
+ config[module] = true;
283
+ }
284
+ }
285
+ return config;
286
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-cli",
3
- "version": "1.24.2",
3
+ "version": "1.25.0",
4
4
  "description": "CLI for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",