@greenarmor/ges-mcp-server 1.2.5 → 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 +123 -18
- package/package.json +12 -12
package/dist/server.js
CHANGED
|
@@ -9,7 +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,
|
|
12
|
+
import { addFrameworkToConfig, removeFrameworkFromConfig, loadControlsFromDisk, recordActivity, recordAIRecommendation } from "@greenarmor/ges-core";
|
|
13
13
|
import { ProjectConfigSchema } from "@greenarmor/ges-core";
|
|
14
14
|
import { generateComplianceDocs, generateSecurityDocs, generateConfigJson, generateMetadataJson, generateFrameworkVersionJson, generateScoreJson } from "@greenarmor/ges-doc-generator";
|
|
15
15
|
import { generateAllWorkflows } from "@greenarmor/ges-cicd-generator";
|
|
@@ -200,13 +200,13 @@ const TOOLS = [
|
|
|
200
200
|
},
|
|
201
201
|
{
|
|
202
202
|
name: "apply_control_override",
|
|
203
|
-
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.",
|
|
204
204
|
inputSchema: {
|
|
205
205
|
type: "object",
|
|
206
206
|
properties: {
|
|
207
207
|
project_path: { type: "string", description: "Absolute path to the project root." },
|
|
208
208
|
control_id: { type: "string", description: "Control ID to override (e.g. GDPR-ART32-004)" },
|
|
209
|
-
status: { type: "string", description: "
|
|
209
|
+
status: { type: "string", description: "Status: only 'not-applicable' is allowed via MCP. 'pass' must come from the audit engine." },
|
|
210
210
|
reason: { type: "string", description: "Reason for the override" },
|
|
211
211
|
},
|
|
212
212
|
},
|
|
@@ -353,6 +353,24 @@ const TOOLS = [
|
|
|
353
353
|
},
|
|
354
354
|
},
|
|
355
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
|
+
},
|
|
356
374
|
];
|
|
357
375
|
function send(message) {
|
|
358
376
|
process.stdout.write(JSON.stringify(message) + "\n");
|
|
@@ -2456,8 +2474,28 @@ export function handleRequest(request) {
|
|
|
2456
2474
|
resultText = "Error: control_id is required.";
|
|
2457
2475
|
break;
|
|
2458
2476
|
}
|
|
2459
|
-
if (
|
|
2460
|
-
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.`;
|
|
2461
2499
|
break;
|
|
2462
2500
|
}
|
|
2463
2501
|
if (!fs.existsSync(path.join(projectPath, ".ges"))) {
|
|
@@ -2486,7 +2524,7 @@ export function handleRequest(request) {
|
|
|
2486
2524
|
`# Control Override Applied\n`,
|
|
2487
2525
|
`**Control**: ${controlId}`,
|
|
2488
2526
|
`**Status**: ${status}`,
|
|
2489
|
-
`**Reason**: ${reason
|
|
2527
|
+
`**Reason**: ${reason}`,
|
|
2490
2528
|
`**File**: ${overridePath}`,
|
|
2491
2529
|
`**Total overrides**: ${overrides.length}\n`,
|
|
2492
2530
|
`The override will take effect on the next \`ges audit\` or \`ges score\` run.`,
|
|
@@ -2582,9 +2620,9 @@ export function handleRequest(request) {
|
|
|
2582
2620
|
}
|
|
2583
2621
|
}
|
|
2584
2622
|
if (appliedCount > 0 || skippedCount > 0) {
|
|
2585
|
-
|
|
2586
|
-
lines.push(
|
|
2587
|
-
lines.push(` The
|
|
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\`.`);
|
|
2588
2626
|
}
|
|
2589
2627
|
const npmInstalls = getNpmInstallsFromActions(plan.actions);
|
|
2590
2628
|
if (npmInstalls.length > 0) {
|
|
@@ -2601,13 +2639,13 @@ export function handleRequest(request) {
|
|
|
2601
2639
|
lines.push(`\n## Next Steps`);
|
|
2602
2640
|
lines.push("1. Install any npm packages listed above");
|
|
2603
2641
|
lines.push("2. Import and integrate the generated files into your app");
|
|
2604
|
-
lines.push("3. Run `ges audit`
|
|
2642
|
+
lines.push("3. Run `ges audit` — GESF will verify the implementation and update the score");
|
|
2605
2643
|
resultText = lines.join("\n");
|
|
2606
2644
|
recordActivity(projectPath, {
|
|
2607
2645
|
source: "mcp",
|
|
2608
2646
|
action: "implement_control",
|
|
2609
2647
|
title: `Control implemented: ${controlId} (${plan.name})`,
|
|
2610
|
-
description: `Auto-implemented control ${controlId} (${plan.name}). ${appliedCount} actions applied, ${skippedCount} skipped.
|
|
2648
|
+
description: `Auto-implemented control ${controlId} (${plan.name}). ${appliedCount} actions applied, ${skippedCount} skipped. Awaiting audit verification.`,
|
|
2611
2649
|
details: { controls_affected: [controlId], files_created: plan.actions.filter(a => a.type === "create").map(a => a.filePath) },
|
|
2612
2650
|
});
|
|
2613
2651
|
break;
|
|
@@ -2722,10 +2760,22 @@ export function handleRequest(request) {
|
|
|
2722
2760
|
fs.writeFileSync(path.join(gesDir, "framework-version.json"), frameworkVersionJson.content);
|
|
2723
2761
|
const scoreJson = generateScoreJson();
|
|
2724
2762
|
fs.writeFileSync(path.join(gesDir, "score.json"), scoreJson.content);
|
|
2725
|
-
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"];
|
|
2726
2764
|
for (const dir of dirs) {
|
|
2727
2765
|
fs.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
2728
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`);
|
|
2729
2779
|
const complianceDocs = generateComplianceDocs(projectName, projectType);
|
|
2730
2780
|
for (const doc of complianceDocs) {
|
|
2731
2781
|
const filePath = path.join(projectPath, COMPLIANCE_DIR, doc.filePath);
|
|
@@ -2989,13 +3039,18 @@ export function handleRequest(request) {
|
|
|
2989
3039
|
const packDir = path.join(projectPath, CONTROLS_DIR, pack.id);
|
|
2990
3040
|
fs.mkdirSync(packDir, { recursive: true });
|
|
2991
3041
|
fs.writeFileSync(path.join(packDir, "controls.json"), JSON.stringify(pack.controls, null, 2));
|
|
2992
|
-
const
|
|
3042
|
+
const frameworksAdded = [];
|
|
3043
|
+
for (const fw of pack.frameworks) {
|
|
3044
|
+
if (addFrameworkToConfig(projectPath, fw)) {
|
|
3045
|
+
frameworksAdded.push(fw);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
2993
3048
|
const lines = [
|
|
2994
3049
|
`✅ Installed policy pack: **${pack.id}** (${pack.name})`,
|
|
2995
3050
|
`${pack.controls.length} controls written to ${CONTROLS_DIR}/${pack.id}/controls.json`,
|
|
2996
3051
|
];
|
|
2997
|
-
if (
|
|
2998
|
-
lines.push(`Added ${
|
|
3052
|
+
if (frameworksAdded.length > 0) {
|
|
3053
|
+
lines.push(`Added ${frameworksAdded.join(", ")} to project frameworks in .ges/config.json`);
|
|
2999
3054
|
}
|
|
3000
3055
|
lines.push(`The web dashboard will now reflect this pack's controls.`);
|
|
3001
3056
|
resultText = lines.join("\n");
|
|
@@ -3003,8 +3058,8 @@ export function handleRequest(request) {
|
|
|
3003
3058
|
source: "mcp",
|
|
3004
3059
|
action: "policy_install",
|
|
3005
3060
|
title: `MCP installed pack: ${pack.name}`,
|
|
3006
|
-
description: `Installed ${pack.controls.length} controls from ${pack.id} pack.${
|
|
3007
|
-
details: { packs_affected: [pack.id], frameworks_added:
|
|
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 },
|
|
3008
3063
|
});
|
|
3009
3064
|
break;
|
|
3010
3065
|
}
|
|
@@ -3021,7 +3076,16 @@ export function handleRequest(request) {
|
|
|
3021
3076
|
break;
|
|
3022
3077
|
}
|
|
3023
3078
|
fs.rmSync(packDir, { recursive: true, force: true });
|
|
3024
|
-
|
|
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
|
+
}
|
|
3025
3089
|
resultText = `✅ Removed policy pack: **${packId}** from ${projectPath}`;
|
|
3026
3090
|
recordActivity(projectPath, {
|
|
3027
3091
|
source: "mcp",
|
|
@@ -3137,6 +3201,47 @@ export function handleRequest(request) {
|
|
|
3137
3201
|
}
|
|
3138
3202
|
break;
|
|
3139
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
|
+
}
|
|
3140
3245
|
default:
|
|
3141
3246
|
return {
|
|
3142
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",
|