@greenarmor/ges-mcp-server 1.2.4 → 1.2.6
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/dist/server.js +216 -10
- package/package.json +12 -12
package/dist/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import { generateScoreFile, formatScoreOutput, computeGrade, generateBadgeSvg, i
|
|
|
9
9
|
import { runAudit, deduplicateFindings } from "@greenarmor/ges-audit-engine";
|
|
10
10
|
import { GESF_VERSION, GES_DIR, COMPLIANCE_DIR, SECURITY_DIR, CONTROLS_DIR, POLICIES_DIR, CHECKLISTS_DIR, DOCS_DIR, REPORTS_DIR, DEFAULT_FRAMEWORKS } from "@greenarmor/ges-core";
|
|
11
11
|
import { appendFixHistory, createFixHistoryEntry } from "@greenarmor/ges-core";
|
|
12
|
+
import { addFrameworkToConfig, removeFrameworkFromConfig, loadControlsFromDisk, recordActivity, recordAIRecommendation } from "@greenarmor/ges-core";
|
|
12
13
|
import { ProjectConfigSchema } from "@greenarmor/ges-core";
|
|
13
14
|
import { generateComplianceDocs, generateSecurityDocs, generateConfigJson, generateMetadataJson, generateFrameworkVersionJson, generateScoreJson } from "@greenarmor/ges-doc-generator";
|
|
14
15
|
import { generateAllWorkflows } from "@greenarmor/ges-cicd-generator";
|
|
@@ -199,13 +200,13 @@ const TOOLS = [
|
|
|
199
200
|
},
|
|
200
201
|
{
|
|
201
202
|
name: "apply_control_override",
|
|
202
|
-
description: "Mark a compliance control as not-applicable
|
|
203
|
+
description: "Mark a compliance control as not-applicable. AI assistants CANNOT mark controls as 'pass' — that must be verified by the GESF audit engine (run_audit). Use 'not-applicable' only when a control genuinely does not apply to the project. A detailed reason is required.",
|
|
203
204
|
inputSchema: {
|
|
204
205
|
type: "object",
|
|
205
206
|
properties: {
|
|
206
207
|
project_path: { type: "string", description: "Absolute path to the project root." },
|
|
207
208
|
control_id: { type: "string", description: "Control ID to override (e.g. GDPR-ART32-004)" },
|
|
208
|
-
status: { type: "string", description: "
|
|
209
|
+
status: { type: "string", description: "Status: only 'not-applicable' is allowed via MCP. 'pass' must come from the audit engine." },
|
|
209
210
|
reason: { type: "string", description: "Reason for the override" },
|
|
210
211
|
},
|
|
211
212
|
},
|
|
@@ -352,6 +353,24 @@ const TOOLS = [
|
|
|
352
353
|
},
|
|
353
354
|
},
|
|
354
355
|
},
|
|
356
|
+
{
|
|
357
|
+
name: "record_recommendation",
|
|
358
|
+
description: "Record a recommendation or observation to .dev-logs/ai-recommendations/ for the GESF development team. Use this when you identify a potential improvement, weakness, or best-practice suggestion. Recommendations are NOT applied automatically — they are logged for human developers to review. This is the correct way to surface ideas instead of overriding controls.",
|
|
359
|
+
inputSchema: {
|
|
360
|
+
type: "object",
|
|
361
|
+
properties: {
|
|
362
|
+
project_path: { type: "string", description: "Absolute path to the project root." },
|
|
363
|
+
category: { type: "string", description: "Category: security, compliance, architecture, performance, best-practice, bug, or improvement." },
|
|
364
|
+
title: { type: "string", description: "Short title for the recommendation." },
|
|
365
|
+
description: { type: "string", description: "Detailed description of the observation." },
|
|
366
|
+
severity: { type: "string", description: "Severity: info, low, medium, or high." },
|
|
367
|
+
affected_controls: { type: "string", description: "Comma-separated control IDs affected (optional)." },
|
|
368
|
+
affected_files: { type: "string", description: "Comma-separated file paths affected (optional)." },
|
|
369
|
+
suggested_action: { type: "string", description: "What you suggest the developers do about this." },
|
|
370
|
+
},
|
|
371
|
+
required: ["project_path", "category", "title", "description", "suggested_action"],
|
|
372
|
+
},
|
|
373
|
+
},
|
|
355
374
|
];
|
|
356
375
|
function send(message) {
|
|
357
376
|
process.stdout.write(JSON.stringify(message) + "\n");
|
|
@@ -2201,6 +2220,14 @@ export function handleRequest(request) {
|
|
|
2201
2220
|
lines.push(`\n*Note: ${projectConfig.overrides.length} control overrides applied.*`);
|
|
2202
2221
|
}
|
|
2203
2222
|
resultText = lines.join("\n");
|
|
2223
|
+
recordActivity(projectPath, {
|
|
2224
|
+
source: "mcp",
|
|
2225
|
+
action: "audit",
|
|
2226
|
+
title: `MCP audit completed`,
|
|
2227
|
+
description: `Scanned ${scannedFiles} files, found ${findings.length} findings (${critical.length} critical, ${high.length} high, ${medium.length} medium, ${low.length} low). Overall score: ${score.overall}%.`,
|
|
2228
|
+
status: critical.length > 0 ? "failed" : findings.length > 0 ? "partial" : "success",
|
|
2229
|
+
details: { findings_count: findings.length, score: score.overall, files_scanned: scannedFiles },
|
|
2230
|
+
});
|
|
2204
2231
|
break;
|
|
2205
2232
|
}
|
|
2206
2233
|
case "generate_compliance_report": {
|
|
@@ -2318,13 +2345,18 @@ export function handleRequest(request) {
|
|
|
2318
2345
|
let projectControls = [];
|
|
2319
2346
|
try {
|
|
2320
2347
|
const configPath = path.join(projectPath, ".ges", "config.json");
|
|
2348
|
+
let inMemoryControls = [];
|
|
2321
2349
|
if (fs.existsSync(configPath)) {
|
|
2322
2350
|
const cfg = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
2323
2351
|
const fwLower = new Set(cfg.frameworks.map((f) => f.toLowerCase()));
|
|
2324
2352
|
const allPacks = getAllPacks();
|
|
2325
2353
|
const filtered = allPacks.filter((pack) => fwLower.has(pack.id.toLowerCase()));
|
|
2326
|
-
|
|
2354
|
+
inMemoryControls = filtered.flatMap((p) => p.controls);
|
|
2327
2355
|
}
|
|
2356
|
+
const diskControls = loadControlsFromDisk(projectPath);
|
|
2357
|
+
const seenIds = new Set(inMemoryControls.map(c => c.id));
|
|
2358
|
+
const extraFromDisk = diskControls.filter(c => !seenIds.has(c.id));
|
|
2359
|
+
projectControls = [...inMemoryControls, ...extraFromDisk];
|
|
2328
2360
|
}
|
|
2329
2361
|
catch { /* ignore */ }
|
|
2330
2362
|
const npmInstalls = getNpmInstallsFromActions(actions);
|
|
@@ -2423,6 +2455,14 @@ export function handleRequest(request) {
|
|
|
2423
2455
|
lines.push("4. Address remaining manual review items");
|
|
2424
2456
|
lines.push("5. Use `fix_recommendation` tool for detailed guidance on manual items");
|
|
2425
2457
|
resultText = lines.join("\n");
|
|
2458
|
+
recordActivity(projectPath, {
|
|
2459
|
+
source: "mcp",
|
|
2460
|
+
action: "fix",
|
|
2461
|
+
title: `MCP auto-fix ${dryRun ? "planned" : "applied"}: ${applied} fixes`,
|
|
2462
|
+
description: `${dryRun ? "Planned" : "Applied"} ${applied} fix(es)${failed > 0 ? ` (${failed} failed)` : ""}. Scanned ${scannedFiles} files, ${findings.length} findings found.`,
|
|
2463
|
+
status: failed > 0 ? "partial" : "success",
|
|
2464
|
+
details: { fixes_applied: applied, findings_count: findings.length },
|
|
2465
|
+
});
|
|
2426
2466
|
break;
|
|
2427
2467
|
}
|
|
2428
2468
|
case "apply_control_override": {
|
|
@@ -2434,8 +2474,28 @@ export function handleRequest(request) {
|
|
|
2434
2474
|
resultText = "Error: control_id is required.";
|
|
2435
2475
|
break;
|
|
2436
2476
|
}
|
|
2437
|
-
if (
|
|
2438
|
-
resultText =
|
|
2477
|
+
if (status === "pass") {
|
|
2478
|
+
resultText = [
|
|
2479
|
+
`# Cannot Override to "pass" via MCP\n`,
|
|
2480
|
+
`AI assistants cannot mark controls as "pass" — this must be verified by GESF's own audit engine.`,
|
|
2481
|
+
``,
|
|
2482
|
+
`**Why**: Allowing AI to set "pass" creates false compliance scores. The audit engine scans actual source code to verify controls are implemented correctly.`,
|
|
2483
|
+
``,
|
|
2484
|
+
`**Instead**:`,
|
|
2485
|
+
`1. Use \`implement_control\` to generate implementation files`,
|
|
2486
|
+
`2. Run \`run_audit\` — GESF will verify the implementation and update the score automatically`,
|
|
2487
|
+
`3. If the control is genuinely not applicable, use status: "not-applicable" with a detailed reason`,
|
|
2488
|
+
``,
|
|
2489
|
+
`**For CLI users**: \`ges control <id> pass --reason "..."'\` is available for human developers who have manually verified.`,
|
|
2490
|
+
].join("\n");
|
|
2491
|
+
break;
|
|
2492
|
+
}
|
|
2493
|
+
if (!["not-applicable"].includes(status)) {
|
|
2494
|
+
resultText = `Error: MCP only allows 'not-applicable'. Use 'not-applicable' for controls that don't apply to this project. Status 'pass' must come from the audit engine.`;
|
|
2495
|
+
break;
|
|
2496
|
+
}
|
|
2497
|
+
if (!reason || reason.trim().length < 10) {
|
|
2498
|
+
resultText = `Error: A detailed reason (at least 10 characters) is required when marking a control as not-applicable. Explain why this control does not apply to your project.`;
|
|
2439
2499
|
break;
|
|
2440
2500
|
}
|
|
2441
2501
|
if (!fs.existsSync(path.join(projectPath, ".ges"))) {
|
|
@@ -2464,13 +2524,20 @@ export function handleRequest(request) {
|
|
|
2464
2524
|
`# Control Override Applied\n`,
|
|
2465
2525
|
`**Control**: ${controlId}`,
|
|
2466
2526
|
`**Status**: ${status}`,
|
|
2467
|
-
`**Reason**: ${reason
|
|
2527
|
+
`**Reason**: ${reason}`,
|
|
2468
2528
|
`**File**: ${overridePath}`,
|
|
2469
2529
|
`**Total overrides**: ${overrides.length}\n`,
|
|
2470
2530
|
`The override will take effect on the next \`ges audit\` or \`ges score\` run.`,
|
|
2471
2531
|
`\nRun \`ges audit\` then \`ges score\` to see the updated compliance score.`,
|
|
2472
2532
|
];
|
|
2473
2533
|
resultText = lines.join("\n");
|
|
2534
|
+
recordActivity(projectPath, {
|
|
2535
|
+
source: "mcp",
|
|
2536
|
+
action: "control_override",
|
|
2537
|
+
title: `Control ${controlId} → ${status}`,
|
|
2538
|
+
description: `MCP applied override: control ${controlId} set to ${status}. Reason: ${reason || "(none)"}`,
|
|
2539
|
+
details: { controls_affected: [controlId] },
|
|
2540
|
+
});
|
|
2474
2541
|
break;
|
|
2475
2542
|
}
|
|
2476
2543
|
case "implement_control": {
|
|
@@ -2536,18 +2603,27 @@ export function handleRequest(request) {
|
|
|
2536
2603
|
break;
|
|
2537
2604
|
}
|
|
2538
2605
|
lines.push(`**Control**: ${plan.name}\n`);
|
|
2606
|
+
let appliedCount = 0;
|
|
2607
|
+
let skippedCount = 0;
|
|
2539
2608
|
for (const action of plan.actions) {
|
|
2540
2609
|
const result = applyAutoFixAction(projectPath, action);
|
|
2541
2610
|
if (result.applied) {
|
|
2611
|
+
appliedCount++;
|
|
2542
2612
|
lines.push(`- ✓ [${action.type}] ${action.filePath}: ${action.description}`);
|
|
2543
2613
|
}
|
|
2544
2614
|
else if (result.error === "File already exists") {
|
|
2615
|
+
skippedCount++;
|
|
2545
2616
|
lines.push(`- → [${action.type}] ${action.filePath}: Already exists (skipped)`);
|
|
2546
2617
|
}
|
|
2547
2618
|
else {
|
|
2548
2619
|
lines.push(`- ✗ [${action.type}] ${action.filePath}: ${result.error}`);
|
|
2549
2620
|
}
|
|
2550
2621
|
}
|
|
2622
|
+
if (appliedCount > 0 || skippedCount > 0) {
|
|
2623
|
+
lines.push(`\n⚠️ **Control status is NOT automatically changed.**`);
|
|
2624
|
+
lines.push(` GESF does not allow AI to self-verify implementations.`);
|
|
2625
|
+
lines.push(` The control will be verified when you run \`ges audit\`.`);
|
|
2626
|
+
}
|
|
2551
2627
|
const npmInstalls = getNpmInstallsFromActions(plan.actions);
|
|
2552
2628
|
if (npmInstalls.length > 0) {
|
|
2553
2629
|
lines.push(`\n## Install Dependencies\n`);
|
|
@@ -2563,9 +2639,15 @@ export function handleRequest(request) {
|
|
|
2563
2639
|
lines.push(`\n## Next Steps`);
|
|
2564
2640
|
lines.push("1. Install any npm packages listed above");
|
|
2565
2641
|
lines.push("2. Import and integrate the generated files into your app");
|
|
2566
|
-
lines.push("3. Run `ges audit`
|
|
2567
|
-
lines.push(`4. Or use \`apply_control_override\` with control_id="${controlId}" if verified manually`);
|
|
2642
|
+
lines.push("3. Run `ges audit` — GESF will verify the implementation and update the score");
|
|
2568
2643
|
resultText = lines.join("\n");
|
|
2644
|
+
recordActivity(projectPath, {
|
|
2645
|
+
source: "mcp",
|
|
2646
|
+
action: "implement_control",
|
|
2647
|
+
title: `Control implemented: ${controlId} (${plan.name})`,
|
|
2648
|
+
description: `Auto-implemented control ${controlId} (${plan.name}). ${appliedCount} actions applied, ${skippedCount} skipped. Awaiting audit verification.`,
|
|
2649
|
+
details: { controls_affected: [controlId], files_created: plan.actions.filter(a => a.type === "create").map(a => a.filePath) },
|
|
2650
|
+
});
|
|
2569
2651
|
break;
|
|
2570
2652
|
}
|
|
2571
2653
|
case "generate_badge": {
|
|
@@ -2678,10 +2760,22 @@ export function handleRequest(request) {
|
|
|
2678
2760
|
fs.writeFileSync(path.join(gesDir, "framework-version.json"), frameworkVersionJson.content);
|
|
2679
2761
|
const scoreJson = generateScoreJson();
|
|
2680
2762
|
fs.writeFileSync(path.join(gesDir, "score.json"), scoreJson.content);
|
|
2681
|
-
const dirs = [COMPLIANCE_DIR, SECURITY_DIR, CONTROLS_DIR, POLICIES_DIR, CHECKLISTS_DIR, DOCS_DIR, REPORTS_DIR];
|
|
2763
|
+
const dirs = [COMPLIANCE_DIR, SECURITY_DIR, CONTROLS_DIR, POLICIES_DIR, CHECKLISTS_DIR, DOCS_DIR, REPORTS_DIR, ".dev-logs"];
|
|
2682
2764
|
for (const dir of dirs) {
|
|
2683
2765
|
fs.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
2684
2766
|
}
|
|
2767
|
+
const gitignorePath = path.join(projectPath, ".gitignore");
|
|
2768
|
+
const devLogsIgnore = ".dev-logs/\n";
|
|
2769
|
+
if (fs.existsSync(gitignorePath)) {
|
|
2770
|
+
const existingGitignore = fs.readFileSync(gitignorePath, "utf-8");
|
|
2771
|
+
if (!existingGitignore.includes(".dev-logs/")) {
|
|
2772
|
+
fs.appendFileSync(gitignorePath, `\n# GESF developer logs (not for remote)\n${devLogsIgnore}`);
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
else {
|
|
2776
|
+
fs.writeFileSync(gitignorePath, `# GESF developer logs (not for remote)\n${devLogsIgnore}\n`);
|
|
2777
|
+
}
|
|
2778
|
+
fs.writeFileSync(path.join(projectPath, ".dev-logs", "README.md"), `# Developer Logs\n\nThis directory is for GESF development notes, session logs, AI recommendations, and release notes.\n\n**This directory is gitignored and intended for developers only. Do not submit to remote.**\n`);
|
|
2685
2779
|
const complianceDocs = generateComplianceDocs(projectName, projectType);
|
|
2686
2780
|
for (const doc of complianceDocs) {
|
|
2687
2781
|
const filePath = path.join(projectPath, COMPLIANCE_DIR, doc.filePath);
|
|
@@ -2725,6 +2819,13 @@ export function handleRequest(request) {
|
|
|
2725
2819
|
lines.push(`3. Run \`ges badge\` to generate a compliance badge for README`);
|
|
2726
2820
|
lines.push(`4. Review and customize documents in compliance/ and security/`);
|
|
2727
2821
|
resultText = lines.join("\n");
|
|
2822
|
+
recordActivity(projectPath, {
|
|
2823
|
+
source: "mcp",
|
|
2824
|
+
action: "init",
|
|
2825
|
+
title: `Project initialized: ${projectName}`,
|
|
2826
|
+
description: `Initialized GESF for ${projectType} project with frameworks: ${frameworks.join(", ")}. Installed ${packs.length} policy packs.`,
|
|
2827
|
+
details: { packs_affected: packs.map(p => p.id), frameworks_added: frameworks.map(f => String(f)) },
|
|
2828
|
+
});
|
|
2728
2829
|
break;
|
|
2729
2830
|
}
|
|
2730
2831
|
case "run_scans": {
|
|
@@ -2755,6 +2856,13 @@ export function handleRequest(request) {
|
|
|
2755
2856
|
lines.push(`\n**${failed.length} scanner(s) reported failures.** Review findings above.`);
|
|
2756
2857
|
}
|
|
2757
2858
|
resultText = lines.join("\n");
|
|
2859
|
+
recordActivity(projectPath, {
|
|
2860
|
+
source: "mcp",
|
|
2861
|
+
action: "scan",
|
|
2862
|
+
title: `MCP security scans completed (${results.length} tools)`,
|
|
2863
|
+
description: `Ran ${results.length} scanner(s) for ${ecosystemDetail} ecosystem. ${results.filter(r => r.status === "pass").length} passed, ${failed.length} failed.`,
|
|
2864
|
+
status: failed.length > 0 ? "partial" : "success",
|
|
2865
|
+
});
|
|
2758
2866
|
break;
|
|
2759
2867
|
}
|
|
2760
2868
|
case "doctor": {
|
|
@@ -2889,6 +2997,13 @@ export function handleRequest(request) {
|
|
|
2889
2997
|
}
|
|
2890
2998
|
lines.push(hasErrors ? "\n❌ **Validation failed.** Fix the issues above." : "\n✅ **All validations passed.**");
|
|
2891
2999
|
resultText = lines.join("\n");
|
|
3000
|
+
recordActivity(projectPath, {
|
|
3001
|
+
source: "mcp",
|
|
3002
|
+
action: "validate",
|
|
3003
|
+
title: `MCP validation ${hasErrors ? "failed" : "passed"}`,
|
|
3004
|
+
description: hasErrors ? "Configuration or directory structure has issues." : "All validations passed.",
|
|
3005
|
+
status: hasErrors ? "failed" : "success",
|
|
3006
|
+
});
|
|
2892
3007
|
break;
|
|
2893
3008
|
}
|
|
2894
3009
|
case "policy_list": {
|
|
@@ -2924,7 +3039,28 @@ export function handleRequest(request) {
|
|
|
2924
3039
|
const packDir = path.join(projectPath, CONTROLS_DIR, pack.id);
|
|
2925
3040
|
fs.mkdirSync(packDir, { recursive: true });
|
|
2926
3041
|
fs.writeFileSync(path.join(packDir, "controls.json"), JSON.stringify(pack.controls, null, 2));
|
|
2927
|
-
|
|
3042
|
+
const frameworksAdded = [];
|
|
3043
|
+
for (const fw of pack.frameworks) {
|
|
3044
|
+
if (addFrameworkToConfig(projectPath, fw)) {
|
|
3045
|
+
frameworksAdded.push(fw);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
const lines = [
|
|
3049
|
+
`✅ Installed policy pack: **${pack.id}** (${pack.name})`,
|
|
3050
|
+
`${pack.controls.length} controls written to ${CONTROLS_DIR}/${pack.id}/controls.json`,
|
|
3051
|
+
];
|
|
3052
|
+
if (frameworksAdded.length > 0) {
|
|
3053
|
+
lines.push(`Added ${frameworksAdded.join(", ")} to project frameworks in .ges/config.json`);
|
|
3054
|
+
}
|
|
3055
|
+
lines.push(`The web dashboard will now reflect this pack's controls.`);
|
|
3056
|
+
resultText = lines.join("\n");
|
|
3057
|
+
recordActivity(projectPath, {
|
|
3058
|
+
source: "mcp",
|
|
3059
|
+
action: "policy_install",
|
|
3060
|
+
title: `MCP installed pack: ${pack.name}`,
|
|
3061
|
+
description: `Installed ${pack.controls.length} controls from ${pack.id} pack.${frameworksAdded.length > 0 ? ` Added ${frameworksAdded.join(", ")} to config frameworks.` : ""}`,
|
|
3062
|
+
details: { packs_affected: [pack.id], frameworks_added: frameworksAdded },
|
|
3063
|
+
});
|
|
2928
3064
|
break;
|
|
2929
3065
|
}
|
|
2930
3066
|
case "policy_remove": {
|
|
@@ -2940,7 +3076,24 @@ export function handleRequest(request) {
|
|
|
2940
3076
|
break;
|
|
2941
3077
|
}
|
|
2942
3078
|
fs.rmSync(packDir, { recursive: true, force: true });
|
|
3079
|
+
const allPacks = getAllPacks();
|
|
3080
|
+
const removedPack = allPacks.find(p => p.id === packId);
|
|
3081
|
+
if (removedPack) {
|
|
3082
|
+
for (const fw of removedPack.frameworks) {
|
|
3083
|
+
removeFrameworkFromConfig(projectPath, fw);
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
else {
|
|
3087
|
+
removeFrameworkFromConfig(projectPath, packId.toUpperCase());
|
|
3088
|
+
}
|
|
2943
3089
|
resultText = `✅ Removed policy pack: **${packId}** from ${projectPath}`;
|
|
3090
|
+
recordActivity(projectPath, {
|
|
3091
|
+
source: "mcp",
|
|
3092
|
+
action: "policy_remove",
|
|
3093
|
+
title: `MCP removed pack: ${packId}`,
|
|
3094
|
+
description: `Removed ${packId} pack and its controls from the project.`,
|
|
3095
|
+
details: { packs_affected: [packId] },
|
|
3096
|
+
});
|
|
2944
3097
|
break;
|
|
2945
3098
|
}
|
|
2946
3099
|
case "update_check": {
|
|
@@ -2991,6 +3144,12 @@ export function handleRequest(request) {
|
|
|
2991
3144
|
fs.writeFileSync(hookPath, hookContent);
|
|
2992
3145
|
fs.chmodSync(hookPath, 0o755);
|
|
2993
3146
|
resultText = `✅ Installed pre-commit hook at ${hookPath}\n\nThe hook will run 'ges audit --ci' before allowing commits.\n- To bypass: \`git commit --no-verify\`\n- To remove: use \`install_hooks\` with action: "uninstall"`;
|
|
3147
|
+
recordActivity(projectPath, {
|
|
3148
|
+
source: "mcp",
|
|
3149
|
+
action: "hooks_install",
|
|
3150
|
+
title: `MCP installed pre-commit hook`,
|
|
3151
|
+
description: `Installed pre-commit hook that runs 'ges audit --ci' before each commit.`,
|
|
3152
|
+
});
|
|
2994
3153
|
break;
|
|
2995
3154
|
}
|
|
2996
3155
|
case "start_dashboard": {
|
|
@@ -3029,6 +3188,12 @@ export function handleRequest(request) {
|
|
|
3029
3188
|
lines.push(`- Control status matrix`);
|
|
3030
3189
|
lines.push(`- Audit history timeline`);
|
|
3031
3190
|
resultText = lines.join("\n");
|
|
3191
|
+
recordActivity(projectPath, {
|
|
3192
|
+
source: "mcp",
|
|
3193
|
+
action: "dashboard_start",
|
|
3194
|
+
title: `Dashboard started on ${host}:${port}`,
|
|
3195
|
+
description: `Web dashboard is running at http://${host}:${port}`,
|
|
3196
|
+
});
|
|
3032
3197
|
}
|
|
3033
3198
|
catch (err) {
|
|
3034
3199
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -3036,6 +3201,47 @@ export function handleRequest(request) {
|
|
|
3036
3201
|
}
|
|
3037
3202
|
break;
|
|
3038
3203
|
}
|
|
3204
|
+
case "record_recommendation": {
|
|
3205
|
+
const projectPath = resolveProjectPath(args.project_path);
|
|
3206
|
+
const category = (args.category || "improvement");
|
|
3207
|
+
const title = args.title || "";
|
|
3208
|
+
const description = args.description || "";
|
|
3209
|
+
const severity = (args.severity || "info");
|
|
3210
|
+
const suggestedAction = args.suggested_action || "";
|
|
3211
|
+
const affectedControls = args.affected_controls ? args.affected_controls.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
3212
|
+
const affectedFiles = args.affected_files ? args.affected_files.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
3213
|
+
if (!title || !description || !suggestedAction) {
|
|
3214
|
+
resultText = "Error: title, description, and suggested_action are all required.";
|
|
3215
|
+
break;
|
|
3216
|
+
}
|
|
3217
|
+
if (!fs.existsSync(projectPath)) {
|
|
3218
|
+
resultText = `Project path does not exist: ${projectPath}`;
|
|
3219
|
+
break;
|
|
3220
|
+
}
|
|
3221
|
+
const rec = recordAIRecommendation(projectPath, {
|
|
3222
|
+
category,
|
|
3223
|
+
title,
|
|
3224
|
+
description,
|
|
3225
|
+
severity,
|
|
3226
|
+
affected_controls: affectedControls,
|
|
3227
|
+
affected_files: affectedFiles,
|
|
3228
|
+
suggested_action: suggestedAction,
|
|
3229
|
+
});
|
|
3230
|
+
resultText = [
|
|
3231
|
+
`# Recommendation Recorded\n`,
|
|
3232
|
+
`**ID**: ${rec.id}`,
|
|
3233
|
+
`**Category**: ${rec.category}`,
|
|
3234
|
+
`**Severity**: ${rec.severity}`,
|
|
3235
|
+
`**Title**: ${rec.title}`,
|
|
3236
|
+
``,
|
|
3237
|
+
`**Written to**: \`.dev-logs/ai-recommendations/\``,
|
|
3238
|
+
``,
|
|
3239
|
+
`This recommendation has been logged for the development team to review.`,
|
|
3240
|
+
`It will NOT be automatically applied to the project.`,
|
|
3241
|
+
`Recommendations are gitignored and intended for developers only.`,
|
|
3242
|
+
].join("\n");
|
|
3243
|
+
break;
|
|
3244
|
+
}
|
|
3039
3245
|
default:
|
|
3040
3246
|
return {
|
|
3041
3247
|
jsonrpc: "2.0",
|
package/package.json
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
"ges-mcp": "dist/server.js"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@greenarmor/ges-audit-engine": "1.2.
|
|
7
|
-
"@greenarmor/ges-cicd-generator": "1.2.
|
|
8
|
-
"@greenarmor/ges-compliance-engine": "1.2.
|
|
9
|
-
"@greenarmor/ges-core": "1.2.
|
|
10
|
-
"@greenarmor/ges-doc-generator": "1.2.
|
|
11
|
-
"@greenarmor/ges-policy-engine": "1.2.
|
|
12
|
-
"@greenarmor/ges-report-generator": "1.2.
|
|
13
|
-
"@greenarmor/ges-rules-engine": "1.2.
|
|
14
|
-
"@greenarmor/ges-scanner-integration": "1.2.
|
|
15
|
-
"@greenarmor/ges-scoring-engine": "1.2.
|
|
16
|
-
"@greenarmor/ges-web-dashboard": "1.2.
|
|
6
|
+
"@greenarmor/ges-audit-engine": "1.2.6",
|
|
7
|
+
"@greenarmor/ges-cicd-generator": "1.2.6",
|
|
8
|
+
"@greenarmor/ges-compliance-engine": "1.2.6",
|
|
9
|
+
"@greenarmor/ges-core": "1.2.6",
|
|
10
|
+
"@greenarmor/ges-doc-generator": "1.2.6",
|
|
11
|
+
"@greenarmor/ges-policy-engine": "1.2.6",
|
|
12
|
+
"@greenarmor/ges-report-generator": "1.2.6",
|
|
13
|
+
"@greenarmor/ges-rules-engine": "1.2.6",
|
|
14
|
+
"@greenarmor/ges-scanner-integration": "1.2.6",
|
|
15
|
+
"@greenarmor/ges-scoring-engine": "1.2.6",
|
|
16
|
+
"@greenarmor/ges-web-dashboard": "1.2.6"
|
|
17
17
|
},
|
|
18
18
|
"description": "GESF MCP Server - AI Compliance Assistant for GDPR, OWASP, NIST, CIS. Check compliance, generate policies, assess risks via MCP protocol.",
|
|
19
19
|
"devDependencies": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"type": "module",
|
|
69
69
|
"types": "./dist/index.d.ts",
|
|
70
|
-
"version": "1.2.
|
|
70
|
+
"version": "1.2.6",
|
|
71
71
|
"scripts": {
|
|
72
72
|
"build": "tsc",
|
|
73
73
|
"clean": "rm -rf dist bundle tsconfig.tsbuildinfo",
|