@bryan-thompson/inspector-assessment-client 1.12.0 → 1.13.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.
@@ -0,0 +1,498 @@
1
+ /**
2
+ * Markdown Report Formatter
3
+ *
4
+ * Generates human-readable markdown reports from MCP assessment results.
5
+ * Designed for reviewers, auditors, and developers.
6
+ *
7
+ * @module MarkdownReportFormatter
8
+ */
9
+ /**
10
+ * Formats assessment results as Markdown
11
+ */
12
+ export class MarkdownReportFormatter {
13
+ options;
14
+ constructor(options = {}) {
15
+ this.options = {
16
+ includeDetails: true,
17
+ includeRecommendations: true,
18
+ ...options,
19
+ };
20
+ }
21
+ /**
22
+ * Format assessment results as markdown
23
+ */
24
+ format(assessment) {
25
+ const sections = [];
26
+ // Header
27
+ sections.push(this.formatHeader(assessment));
28
+ // Executive Summary
29
+ sections.push(this.formatExecutiveSummary(assessment));
30
+ // Module Status Table
31
+ sections.push(this.formatModuleStatusTable(assessment));
32
+ // Key Findings
33
+ sections.push(this.formatKeyFindings(assessment));
34
+ // Policy Compliance (if enabled)
35
+ if (this.options.includePolicy && this.options.policyReport) {
36
+ sections.push(this.formatPolicyCompliance(this.options.policyReport));
37
+ }
38
+ // Recommendations
39
+ if (this.options.includeRecommendations) {
40
+ sections.push(this.formatRecommendations(assessment));
41
+ }
42
+ // Detailed Results (if enabled)
43
+ if (this.options.includeDetails) {
44
+ sections.push(this.formatDetailedResults(assessment));
45
+ }
46
+ // Footer
47
+ sections.push(this.formatFooter(assessment));
48
+ return sections.filter(Boolean).join("\n\n---\n\n");
49
+ }
50
+ /**
51
+ * Format header section
52
+ */
53
+ formatHeader(assessment) {
54
+ const serverName = this.options.serverName || assessment.serverName;
55
+ const statusEmoji = this.getStatusEmoji(assessment.overallStatus);
56
+ return `# MCP Server Assessment Report
57
+
58
+ **Server**: ${serverName}
59
+ **Date**: ${new Date(assessment.assessmentDate).toLocaleString()}
60
+ **Status**: ${statusEmoji} ${assessment.overallStatus}
61
+ **Version**: ${assessment.assessorVersion}`;
62
+ }
63
+ /**
64
+ * Format executive summary
65
+ */
66
+ formatExecutiveSummary(assessment) {
67
+ const lines = ["## Executive Summary", ""];
68
+ lines.push("| Metric | Value |");
69
+ lines.push("|--------|-------|");
70
+ // Tools count
71
+ const workingCount = assessment.functionality?.workingTools ?? 0;
72
+ const brokenCount = assessment.functionality?.brokenTools?.length ?? 0;
73
+ lines.push(`| Tools Tested | ${workingCount + brokenCount} |`);
74
+ // Success rate
75
+ const successRate = assessment.functionality?.coveragePercentage ??
76
+ (workingCount > 0
77
+ ? Math.round((workingCount / (workingCount + brokenCount)) * 100)
78
+ : 0);
79
+ lines.push(`| Tool Success Rate | ${successRate}% |`);
80
+ // Vulnerabilities
81
+ const vulnCount = assessment.security?.vulnerabilities?.length ?? 0;
82
+ lines.push(`| Security Vulnerabilities | ${vulnCount === 0 ? "None" : vulnCount} |`);
83
+ // Total tests
84
+ lines.push(`| Total Tests Run | ${assessment.totalTestsRun} |`);
85
+ // Execution time
86
+ const execTime = (assessment.executionTime / 1000).toFixed(1);
87
+ lines.push(`| Execution Time | ${execTime}s |`);
88
+ return lines.join("\n");
89
+ }
90
+ /**
91
+ * Format module status table
92
+ */
93
+ formatModuleStatusTable(assessment) {
94
+ const lines = ["## Module Status", ""];
95
+ lines.push("| Module | Status | Key Finding |");
96
+ lines.push("|--------|--------|-------------|");
97
+ // Core modules
98
+ lines.push(this.formatModuleRow("Functionality", assessment.functionality?.status, this.getFunctionalityFinding(assessment)));
99
+ lines.push(this.formatModuleRow("Security", assessment.security?.status, this.getSecurityFinding(assessment)));
100
+ lines.push(this.formatModuleRow("Error Handling", assessment.errorHandling?.status, this.getErrorHandlingFinding(assessment)));
101
+ lines.push(this.formatModuleRow("Documentation", assessment.documentation?.status, this.getDocumentationFinding(assessment)));
102
+ lines.push(this.formatModuleRow("Usability", assessment.usability?.status, this.getUsabilityFinding(assessment)));
103
+ // Extended modules (if present)
104
+ if (assessment.mcpSpecCompliance) {
105
+ lines.push(this.formatModuleRow("MCP Spec Compliance", assessment.mcpSpecCompliance.status, this.getMCPSpecFinding(assessment)));
106
+ }
107
+ if (assessment.aupCompliance) {
108
+ lines.push(this.formatModuleRow("AUP Compliance", assessment.aupCompliance.status, this.getAUPFinding(assessment)));
109
+ }
110
+ if (assessment.toolAnnotations) {
111
+ lines.push(this.formatModuleRow("Tool Annotations", assessment.toolAnnotations.status, this.getAnnotationFinding(assessment)));
112
+ }
113
+ return lines.join("\n");
114
+ }
115
+ /**
116
+ * Format a single module row
117
+ */
118
+ formatModuleRow(name, status, finding) {
119
+ const statusEmoji = this.getStatusEmoji(status);
120
+ const displayStatus = status || "NOT_RUN";
121
+ return `| ${name} | ${statusEmoji} ${displayStatus} | ${finding} |`;
122
+ }
123
+ /**
124
+ * Format key findings section
125
+ */
126
+ formatKeyFindings(assessment) {
127
+ const lines = ["## Key Findings", ""];
128
+ // Critical Issues
129
+ const criticalIssues = this.getCriticalIssues(assessment);
130
+ if (criticalIssues.length > 0) {
131
+ lines.push("### Critical Issues");
132
+ for (const issue of criticalIssues) {
133
+ lines.push(`- ${issue}`);
134
+ }
135
+ lines.push("");
136
+ }
137
+ // Warnings
138
+ const warnings = this.getWarnings(assessment);
139
+ if (warnings.length > 0) {
140
+ lines.push("### Warnings");
141
+ for (const warning of warnings) {
142
+ lines.push(`- ${warning}`);
143
+ }
144
+ lines.push("");
145
+ }
146
+ // Positive findings
147
+ const positives = this.getPositiveFindings(assessment);
148
+ if (positives.length > 0) {
149
+ lines.push("### Positive Findings");
150
+ for (const positive of positives) {
151
+ lines.push(`- ${positive}`);
152
+ }
153
+ }
154
+ return lines.join("\n");
155
+ }
156
+ /**
157
+ * Format policy compliance section
158
+ */
159
+ formatPolicyCompliance(report) {
160
+ const lines = ["## Policy Compliance", ""];
161
+ // Summary
162
+ lines.push("### Compliance Summary");
163
+ lines.push("");
164
+ lines.push("| Metric | Value |");
165
+ lines.push("|--------|-------|");
166
+ lines.push(`| Total Requirements | ${report.summary.totalRequirements} |`);
167
+ lines.push(`| Passed | ${report.summary.passed} |`);
168
+ lines.push(`| Failed | ${report.summary.failed} |`);
169
+ lines.push(`| Needs Review | ${report.summary.needsReview} |`);
170
+ lines.push(`| Compliance Score | ${report.summary.complianceScore}% |`);
171
+ lines.push(`| Overall Status | ${this.getStatusEmoji(this.complianceToAssessment(report.summary.overallStatus))} ${report.summary.overallStatus} |`);
172
+ lines.push("");
173
+ // Category breakdown
174
+ lines.push("### By Category");
175
+ lines.push("");
176
+ lines.push("| Category | Status | Passed | Failed |");
177
+ lines.push("|----------|--------|--------|--------|");
178
+ for (const [, category] of Object.entries(report.byCategory)) {
179
+ const statusEmoji = this.getComplianceStatusEmoji(category.status);
180
+ lines.push(`| ${category.categoryName} | ${statusEmoji} ${category.status} | ${category.passed}/${category.total} | ${category.failed} |`);
181
+ }
182
+ lines.push("");
183
+ // Critical issues from policy
184
+ if (report.criticalIssues.length > 0) {
185
+ lines.push("### Critical Policy Issues");
186
+ lines.push("");
187
+ for (const issue of report.criticalIssues.slice(0, 5)) {
188
+ lines.push(`- **${issue.requirement.id}**: ${issue.requirement.name} - ${issue.status}`);
189
+ if (issue.recommendation) {
190
+ lines.push(` - ${issue.recommendation}`);
191
+ }
192
+ }
193
+ lines.push("");
194
+ }
195
+ // Action items
196
+ if (report.actionItems.length > 0) {
197
+ lines.push("### Action Items");
198
+ lines.push("");
199
+ for (const item of report.actionItems) {
200
+ lines.push(`- ${item}`);
201
+ }
202
+ }
203
+ return lines.join("\n");
204
+ }
205
+ /**
206
+ * Format recommendations section
207
+ */
208
+ formatRecommendations(assessment) {
209
+ const lines = ["## Recommendations", ""];
210
+ const recs = assessment.recommendations || [];
211
+ if (recs.length === 0) {
212
+ lines.push("No recommendations at this time.");
213
+ return lines.join("\n");
214
+ }
215
+ // Group by priority
216
+ const high = recs.filter((r) => r.toLowerCase().includes("critical") ||
217
+ r.toLowerCase().includes("security"));
218
+ const medium = recs.filter((r) => !high.includes(r) &&
219
+ (r.toLowerCase().includes("required") ||
220
+ r.toLowerCase().includes("must")));
221
+ const low = recs.filter((r) => !high.includes(r) && !medium.includes(r));
222
+ if (high.length > 0) {
223
+ lines.push("### High Priority");
224
+ for (const rec of high) {
225
+ lines.push(`1. ${rec}`);
226
+ }
227
+ lines.push("");
228
+ }
229
+ if (medium.length > 0) {
230
+ lines.push("### Medium Priority");
231
+ for (const rec of medium) {
232
+ lines.push(`1. ${rec}`);
233
+ }
234
+ lines.push("");
235
+ }
236
+ if (low.length > 0) {
237
+ lines.push("### Other");
238
+ for (const rec of low.slice(0, 5)) {
239
+ lines.push(`1. ${rec}`);
240
+ }
241
+ }
242
+ return lines.join("\n");
243
+ }
244
+ /**
245
+ * Format detailed results section
246
+ */
247
+ formatDetailedResults(assessment) {
248
+ const lines = ["## Detailed Results", ""];
249
+ // Functionality details
250
+ if (assessment.functionality) {
251
+ lines.push("### Functionality");
252
+ lines.push("");
253
+ lines.push(`**Status**: ${assessment.functionality.status}`);
254
+ lines.push("");
255
+ const workingCount = assessment.functionality.workingTools ?? 0;
256
+ const brokenTools = assessment.functionality.brokenTools || [];
257
+ if (workingCount > 0) {
258
+ lines.push(`**Working Tools**: ${workingCount} tool(s) functioning correctly`);
259
+ }
260
+ if (brokenTools.length > 0) {
261
+ lines.push("");
262
+ lines.push(`**Broken Tools** (${brokenTools.length}):`);
263
+ for (const tool of brokenTools.slice(0, 5)) {
264
+ lines.push(`- ${tool}`);
265
+ }
266
+ }
267
+ lines.push("");
268
+ }
269
+ // Security details
270
+ if (assessment.security) {
271
+ lines.push("### Security");
272
+ lines.push("");
273
+ lines.push(`**Status**: ${assessment.security.status}`);
274
+ lines.push("");
275
+ const vulns = assessment.security.vulnerabilities || [];
276
+ if (vulns.length > 0) {
277
+ lines.push(`**Vulnerabilities Found** (${vulns.length}):`);
278
+ for (const vuln of vulns.slice(0, 5)) {
279
+ lines.push(`- ${vuln}`);
280
+ }
281
+ }
282
+ else {
283
+ lines.push("No vulnerabilities detected.");
284
+ }
285
+ lines.push("");
286
+ }
287
+ // Tool Annotations details
288
+ if (assessment.toolAnnotations) {
289
+ lines.push("### Tool Annotations");
290
+ lines.push("");
291
+ lines.push(`**Status**: ${assessment.toolAnnotations.status}`);
292
+ lines.push(`**Coverage**: ${assessment.toolAnnotations.annotatedCount} annotated, ${assessment.toolAnnotations.missingAnnotationsCount} missing`);
293
+ if (assessment.toolAnnotations.annotationSources) {
294
+ const sources = assessment.toolAnnotations.annotationSources;
295
+ lines.push("");
296
+ lines.push("**Annotation Sources**:");
297
+ lines.push(`- MCP Protocol: ${sources.mcp}`);
298
+ lines.push(`- Source Code: ${sources.sourceCode}`);
299
+ lines.push(`- Inferred: ${sources.inferred}`);
300
+ lines.push(`- None: ${sources.none}`);
301
+ }
302
+ lines.push("");
303
+ }
304
+ return lines.join("\n");
305
+ }
306
+ /**
307
+ * Format footer section
308
+ */
309
+ formatFooter(assessment) {
310
+ return `## Report Metadata
311
+
312
+ - **Generated**: ${new Date().toISOString()}
313
+ - **Assessor Version**: ${assessment.assessorVersion}
314
+ - **MCP Protocol Version**: ${assessment.mcpProtocolVersion || "N/A"}
315
+ - **Total Tests**: ${assessment.totalTestsRun}
316
+ - **Execution Time**: ${(assessment.executionTime / 1000).toFixed(2)}s
317
+
318
+ ---
319
+
320
+ *Generated by MCP Inspector Assessment CLI*`;
321
+ }
322
+ // ============================================================================
323
+ // Helper Methods
324
+ // ============================================================================
325
+ getStatusEmoji(status) {
326
+ switch (status) {
327
+ case "PASS":
328
+ return "✅";
329
+ case "FAIL":
330
+ return "❌";
331
+ case "NEED_MORE_INFO":
332
+ return "⚠️";
333
+ default:
334
+ return "❓";
335
+ }
336
+ }
337
+ getComplianceStatusEmoji(status) {
338
+ switch (status) {
339
+ case "PASS":
340
+ return "✅";
341
+ case "FAIL":
342
+ return "❌";
343
+ case "FLAG":
344
+ return "🚩";
345
+ case "REVIEW":
346
+ return "🔍";
347
+ case "NOT_APPLICABLE":
348
+ return "➖";
349
+ case "NOT_TESTED":
350
+ return "❓";
351
+ default:
352
+ return "❓";
353
+ }
354
+ }
355
+ complianceToAssessment(status) {
356
+ switch (status) {
357
+ case "COMPLIANT":
358
+ return "PASS";
359
+ case "NON_COMPLIANT":
360
+ return "FAIL";
361
+ case "NEEDS_REVIEW":
362
+ return "NEED_MORE_INFO";
363
+ }
364
+ }
365
+ getFunctionalityFinding(assessment) {
366
+ const working = assessment.functionality?.workingTools ?? 0;
367
+ const broken = assessment.functionality?.brokenTools?.length ?? 0;
368
+ const total = working + broken;
369
+ if (total === 0)
370
+ return "No tools tested";
371
+ if (broken === 0)
372
+ return `All ${total} tools working`;
373
+ return `${working}/${total} tools working, ${broken} failing`;
374
+ }
375
+ getSecurityFinding(assessment) {
376
+ const vulns = assessment.security?.vulnerabilities?.length ?? 0;
377
+ if (vulns === 0)
378
+ return "No vulnerabilities detected";
379
+ return `${vulns} vulnerability(ies) detected`;
380
+ }
381
+ getErrorHandlingFinding(assessment) {
382
+ const metrics = assessment.errorHandling?.metrics;
383
+ if (!metrics)
384
+ return "Not tested";
385
+ const passRate = metrics.validationCoverage?.overallPassRate ?? 0;
386
+ return `${passRate}% pass rate`;
387
+ }
388
+ getDocumentationFinding(assessment) {
389
+ const status = assessment.documentation?.status;
390
+ if (!status)
391
+ return "Not assessed";
392
+ return status === "PASS"
393
+ ? "Documentation adequate"
394
+ : "Documentation needs improvement";
395
+ }
396
+ getUsabilityFinding(assessment) {
397
+ const status = assessment.usability?.status;
398
+ if (!status)
399
+ return "Not assessed";
400
+ return status === "PASS" ? "Good usability" : "Usability issues found";
401
+ }
402
+ getMCPSpecFinding(assessment) {
403
+ const status = assessment.mcpSpecCompliance?.status;
404
+ if (!status)
405
+ return "Not tested";
406
+ return status === "PASS" ? "Protocol compliant" : "Protocol issues found";
407
+ }
408
+ getAUPFinding(assessment) {
409
+ const violations = assessment.aupCompliance?.violations?.length ?? 0;
410
+ if (violations === 0)
411
+ return "No AUP violations";
412
+ return `${violations} AUP violation(s) detected`;
413
+ }
414
+ getAnnotationFinding(assessment) {
415
+ const annotated = assessment.toolAnnotations?.annotatedCount ?? 0;
416
+ const missing = assessment.toolAnnotations?.missingAnnotationsCount ?? 0;
417
+ if (annotated === 0 && missing === 0)
418
+ return "No tools assessed";
419
+ if (missing === 0)
420
+ return `All ${annotated} tools annotated`;
421
+ return `${annotated} annotated, ${missing} missing`;
422
+ }
423
+ getCriticalIssues(assessment) {
424
+ const issues = [];
425
+ // Security vulnerabilities
426
+ const vulns = assessment.security?.vulnerabilities || [];
427
+ if (vulns.length > 0) {
428
+ issues.push(`${vulns.length} security vulnerability(ies) detected`);
429
+ }
430
+ // AUP violations
431
+ const aupViolations = assessment.aupCompliance?.violations || [];
432
+ const critical = aupViolations.filter((v) => typeof v === "object" &&
433
+ v !== null &&
434
+ v.severity === "CRITICAL");
435
+ if (critical.length > 0) {
436
+ issues.push(`${critical.length} critical AUP violation(s)`);
437
+ }
438
+ // Broken tools
439
+ const broken = assessment.functionality?.brokenTools || [];
440
+ if (broken.length > 0) {
441
+ issues.push(`${broken.length} tool(s) not functioning correctly`);
442
+ }
443
+ return issues;
444
+ }
445
+ getWarnings(assessment) {
446
+ const warnings = [];
447
+ // Missing annotations
448
+ const missing = assessment.toolAnnotations?.missingAnnotationsCount ?? 0;
449
+ if (missing > 0) {
450
+ warnings.push(`${missing} tool(s) missing required annotations`);
451
+ }
452
+ // Misaligned annotations
453
+ const misaligned = assessment.toolAnnotations?.misalignedAnnotationsCount ?? 0;
454
+ if (misaligned > 0) {
455
+ warnings.push(`${misaligned} tool(s) with potentially misaligned annotations`);
456
+ }
457
+ // Error handling issues
458
+ const errorMetrics = assessment.errorHandling?.metrics;
459
+ const passRate = errorMetrics?.validationCoverage?.overallPassRate ?? 100;
460
+ if (errorMetrics && passRate < 80) {
461
+ warnings.push(`Low error handling pass rate (${passRate}%)`);
462
+ }
463
+ return warnings;
464
+ }
465
+ getPositiveFindings(assessment) {
466
+ const positives = [];
467
+ // All tools working
468
+ const working = assessment.functionality?.workingTools ?? 0;
469
+ const broken = assessment.functionality?.brokenTools?.length ?? 0;
470
+ if (working > 0 && broken === 0) {
471
+ positives.push(`All ${working} tools functioning correctly`);
472
+ }
473
+ // No security vulnerabilities
474
+ const vulns = assessment.security?.vulnerabilities?.length ?? 0;
475
+ if (vulns === 0) {
476
+ positives.push("No security vulnerabilities detected");
477
+ }
478
+ // Full annotation coverage
479
+ const annotated = assessment.toolAnnotations?.annotatedCount ?? 0;
480
+ const missingAnnotations = assessment.toolAnnotations?.missingAnnotationsCount ?? 0;
481
+ if (annotated > 0 && missingAnnotations === 0) {
482
+ positives.push(`All ${annotated} tools have required annotations`);
483
+ }
484
+ // Good error handling
485
+ const errorMetrics2 = assessment.errorHandling?.metrics;
486
+ const passRate2 = errorMetrics2?.validationCoverage?.overallPassRate ?? 0;
487
+ if (errorMetrics2 && passRate2 >= 90) {
488
+ positives.push("Excellent error handling coverage");
489
+ }
490
+ return positives;
491
+ }
492
+ }
493
+ /**
494
+ * Create a markdown formatter with options
495
+ */
496
+ export function createMarkdownFormatter(options) {
497
+ return new MarkdownReportFormatter(options);
498
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Report Formatters
3
+ *
4
+ * Factory module for creating report formatters in different output formats.
5
+ *
6
+ * @module reportFormatters
7
+ */
8
+ import type { MCPDirectoryAssessment } from "../assessmentTypes.js";
9
+ import type { PolicyComplianceReport } from "../policyMapping.js";
10
+ import { MarkdownReportFormatter, type MarkdownReportOptions } from "./MarkdownReportFormatter.js";
11
+ /**
12
+ * Supported output formats
13
+ */
14
+ export type ReportFormat = "json" | "markdown";
15
+ /**
16
+ * Base formatter interface
17
+ */
18
+ export interface ReportFormatter {
19
+ /** Format the assessment results */
20
+ format(assessment: MCPDirectoryAssessment): string;
21
+ /** Get the file extension for this format */
22
+ getFileExtension(): string;
23
+ }
24
+ /**
25
+ * Options for creating a formatter
26
+ */
27
+ export interface FormatterOptions {
28
+ /** Output format */
29
+ format: ReportFormat;
30
+ /** Include policy compliance mapping */
31
+ includePolicyMapping?: boolean;
32
+ /** Policy compliance report (generated separately) */
33
+ policyReport?: PolicyComplianceReport;
34
+ /** Server name override */
35
+ serverName?: string;
36
+ /** Include detailed results */
37
+ includeDetails?: boolean;
38
+ /** Pretty print JSON */
39
+ prettyPrint?: boolean;
40
+ }
41
+ /**
42
+ * Create a formatter based on options
43
+ */
44
+ export declare function createFormatter(options: FormatterOptions): ReportFormatter;
45
+ /**
46
+ * Quick format utility
47
+ */
48
+ export declare function formatAssessmentReport(assessment: MCPDirectoryAssessment, format?: ReportFormat, options?: Partial<FormatterOptions>): string;
49
+ export { MarkdownReportFormatter, type MarkdownReportOptions };
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/reportFormatters/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,uBAAuB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,MAAM,CAAC,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAAC;IACnD,6CAA6C;IAC7C,gBAAgB,IAAI,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,sDAAsD;IACtD,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA8DD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAQ1E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,sBAAsB,EAClC,MAAM,GAAE,YAAqB,EAC7B,OAAO,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAClC,MAAM,CAMR;AAGD,OAAO,EAAE,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Report Formatters
3
+ *
4
+ * Factory module for creating report formatters in different output formats.
5
+ *
6
+ * @module reportFormatters
7
+ */
8
+ import { MarkdownReportFormatter, } from "./MarkdownReportFormatter.js";
9
+ /**
10
+ * JSON formatter implementation
11
+ */
12
+ class JSONReportFormatter {
13
+ options;
14
+ constructor(options) {
15
+ this.options = options;
16
+ }
17
+ format(assessment) {
18
+ const output = {
19
+ ...assessment,
20
+ };
21
+ // Add policy compliance if included
22
+ if (this.options.includePolicyMapping && this.options.policyReport) {
23
+ output.policyCompliance = this.options.policyReport;
24
+ }
25
+ // Override server name if provided
26
+ if (this.options.serverName) {
27
+ output.serverName = this.options.serverName;
28
+ }
29
+ const indent = this.options.prettyPrint !== false ? 2 : undefined;
30
+ return JSON.stringify(output, null, indent);
31
+ }
32
+ getFileExtension() {
33
+ return ".json";
34
+ }
35
+ }
36
+ /**
37
+ * Markdown formatter wrapper
38
+ */
39
+ class MarkdownFormatterWrapper {
40
+ formatter;
41
+ constructor(options) {
42
+ const mdOptions = {
43
+ includePolicy: options.includePolicyMapping,
44
+ policyReport: options.policyReport,
45
+ includeDetails: options.includeDetails ?? true,
46
+ includeRecommendations: true,
47
+ serverName: options.serverName,
48
+ };
49
+ this.formatter = new MarkdownReportFormatter(mdOptions);
50
+ }
51
+ format(assessment) {
52
+ return this.formatter.format(assessment);
53
+ }
54
+ getFileExtension() {
55
+ return ".md";
56
+ }
57
+ }
58
+ /**
59
+ * Create a formatter based on options
60
+ */
61
+ export function createFormatter(options) {
62
+ switch (options.format) {
63
+ case "markdown":
64
+ return new MarkdownFormatterWrapper(options);
65
+ case "json":
66
+ default:
67
+ return new JSONReportFormatter(options);
68
+ }
69
+ }
70
+ /**
71
+ * Quick format utility
72
+ */
73
+ export function formatAssessmentReport(assessment, format = "json", options) {
74
+ const formatter = createFormatter({
75
+ format,
76
+ ...options,
77
+ });
78
+ return formatter.format(assessment);
79
+ }
80
+ // Re-export types and classes
81
+ export { MarkdownReportFormatter };
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Backend API Security Patterns
3
- * Tests MCP server API security with 13 focused patterns
3
+ * Tests MCP server API security with 16 focused patterns
4
4
  *
5
5
  * Architecture: Attack-Type with Specific Payloads
6
6
  * - Critical Injection (4 patterns): Command, Calculator, SQL, Path Traversal
7
7
  * - Input Validation (3 patterns): Type Safety, Boundary Testing, Required Fields
8
8
  * - Protocol Compliance (2 patterns): MCP Error Format, Timeout Handling
9
- * - Tool-Specific Vulnerabilities (4 patterns): Indirect Injection, Unicode Bypass, Nested Injection, Package Squatting
9
+ * - Tool-Specific Vulnerabilities (7 patterns): Indirect Injection, Unicode Bypass, Nested Injection, Package Squatting, Data Exfiltration, Configuration Drift, Tool Shadowing
10
10
  *
11
11
  * Scope: Backend API Security ONLY
12
12
  * - Tests structured data inputs to API endpoints
@@ -38,7 +38,7 @@ export interface AttackPattern {
38
38
  * BACKEND API SECURITY PATTERNS
39
39
  * ========================================
40
40
  *
41
- * 13 focused patterns for MCP server API security
41
+ * 16 focused patterns for MCP server API security
42
42
  */
43
43
  export declare const SECURITY_ATTACK_PATTERNS: AttackPattern[];
44
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"securityPatterns.d.ts","sourceRoot":"","sources":["../../src/lib/securityPatterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAAa,EAgZnD,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,eAAe,EAAE,CAQnB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,EAAE,CAEtD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;;;;;;;;EA8BnC"}
1
+ {"version":3,"file":"securityPatterns.d.ts","sourceRoot":"","sources":["../../src/lib/securityPatterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAAa,EA+hBnD,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,eAAe,EAAE,CAQnB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,EAAE,CAEtD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;;;;;;;;EA8BnC"}