@greenarmor/ges-mcp-server 1.2.0 → 1.2.2

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.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import type { Finding } from "@greenarmor/ges-audit-engine";
3
+ export declare function stopDashboardServer(): void;
3
4
  export type AutoFixAction = {
4
5
  type: "create" | "modify" | "append" | "npm-install";
5
6
  filePath: string;
package/dist/server.js CHANGED
@@ -8,10 +8,22 @@ const HT = ["http", "//"].join(":");
8
8
  import { generateScoreFile, formatScoreOutput, computeGrade, generateBadgeSvg, injectBadgeIntoReadme, generateScoreExplainer } from "@greenarmor/ges-scoring-engine";
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
+ import { appendFixHistory, createFixHistoryEntry } from "@greenarmor/ges-core";
11
12
  import { ProjectConfigSchema } from "@greenarmor/ges-core";
12
13
  import { generateComplianceDocs, generateSecurityDocs, generateConfigJson, generateMetadataJson, generateFrameworkVersionJson, generateScoreJson } from "@greenarmor/ges-doc-generator";
13
14
  import { generateAllWorkflows } from "@greenarmor/ges-cicd-generator";
14
15
  import { detectProject, runAllScansWithSbom, formatScanResults, formatSbomResults } from "@greenarmor/ges-scanner-integration";
16
+ import { startDashboard } from "@greenarmor/ges-web-dashboard";
17
+ let activeDashboardServer = null;
18
+ export function stopDashboardServer() {
19
+ if (activeDashboardServer) {
20
+ try {
21
+ activeDashboardServer.close();
22
+ }
23
+ catch { /* ignore */ }
24
+ activeDashboardServer = null;
25
+ }
26
+ }
15
27
  const TOOLS = [
16
28
  {
17
29
  name: "check_compliance",
@@ -2130,6 +2142,21 @@ export function handleRequest(request) {
2130
2142
  const overriddenControls = applyControlOverrides(controls, projectConfig.overrides);
2131
2143
  const auditedControls = updateControlsFromFindings(overriddenControls, findings);
2132
2144
  const score = generateScoreFile(auditedControls, frameworks, findings);
2145
+ try {
2146
+ fs.writeFileSync(path.join(projectPath, ".ges", "last-audit.json"), JSON.stringify({
2147
+ findings, scannedFiles, timestamp: new Date().toISOString(),
2148
+ }, null, 2));
2149
+ fs.writeFileSync(path.join(projectPath, ".ges", "score.json"), JSON.stringify(score, null, 2));
2150
+ const metaPath = path.join(projectPath, ".ges", "metadata.json");
2151
+ let meta = {};
2152
+ try {
2153
+ meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
2154
+ }
2155
+ catch { /* ignore */ }
2156
+ meta.last_audit = new Date().toISOString();
2157
+ fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
2158
+ }
2159
+ catch { /* ignore persistence errors */ }
2133
2160
  const critical = findings.filter(f => f.severity === "critical");
2134
2161
  const high = findings.filter(f => f.severity === "high");
2135
2162
  const medium = findings.filter(f => f.severity === "medium");
@@ -2260,6 +2287,12 @@ export function handleRequest(request) {
2260
2287
  }
2261
2288
  const { findings: rawFindings, scannedFiles } = runAudit(projectPath);
2262
2289
  const findings = deduplicateFindings(rawFindings);
2290
+ try {
2291
+ fs.writeFileSync(path.join(projectPath, ".ges", "last-audit.json"), JSON.stringify({
2292
+ findings, scannedFiles, timestamp: new Date().toISOString(),
2293
+ }, null, 2));
2294
+ }
2295
+ catch { /* ignore persistence errors */ }
2263
2296
  if (findings.length === 0) {
2264
2297
  resultText = `# Auto-Fix Report\n\n**Project**: ${projectPath}\n**Scanned**: ${scannedFiles} files\n\nNo issues found. Project is clean!`;
2265
2298
  break;
@@ -2282,6 +2315,18 @@ export function handleRequest(request) {
2282
2315
  resultText = lines.join("\n");
2283
2316
  break;
2284
2317
  }
2318
+ let projectControls = [];
2319
+ try {
2320
+ const configPath = path.join(projectPath, ".ges", "config.json");
2321
+ if (fs.existsSync(configPath)) {
2322
+ const cfg = JSON.parse(fs.readFileSync(configPath, "utf-8"));
2323
+ const fwLower = new Set(cfg.frameworks.map((f) => f.toLowerCase()));
2324
+ const allPacks = getAllPacks();
2325
+ const filtered = allPacks.filter((pack) => fwLower.has(pack.id.toLowerCase()));
2326
+ projectControls = filtered.flatMap((p) => p.controls);
2327
+ }
2328
+ }
2329
+ catch { /* ignore */ }
2285
2330
  const npmInstalls = getNpmInstallsFromActions(actions);
2286
2331
  const lines = [
2287
2332
  `# Auto-Fix Report\n`,
@@ -2300,10 +2345,28 @@ export function handleRequest(request) {
2300
2345
  }
2301
2346
  let applied = 0;
2302
2347
  let failed = 0;
2348
+ const historyEntries = [];
2303
2349
  for (const action of actions) {
2350
+ const matchingFindings = findings.filter(f => f.ruleId === action.ruleId);
2351
+ const primaryFinding = matchingFindings[0];
2352
+ const matchedControls = primaryFinding
2353
+ ? projectControls.filter((c) => primaryFinding.controlIds.includes(c.id))
2354
+ : [];
2304
2355
  if (dryRun) {
2305
2356
  lines.push(`- [${action.type}] ${action.filePath}: ${action.description}`);
2306
2357
  applied++;
2358
+ historyEntries.push(createFixHistoryEntry({
2359
+ source: "mcp",
2360
+ dry_run: true,
2361
+ finding: primaryFinding ?? {
2362
+ ruleId: action.ruleId, severity: "medium", category: "",
2363
+ title: action.description, file: "", evidence: "",
2364
+ description: action.description, controlIds: [], fix: action.description,
2365
+ },
2366
+ action,
2367
+ controls: matchedControls,
2368
+ applied: false,
2369
+ }));
2307
2370
  }
2308
2371
  else {
2309
2372
  const result = applyAutoFixAction(projectPath, action);
@@ -2315,10 +2378,29 @@ export function handleRequest(request) {
2315
2378
  failed++;
2316
2379
  lines.push(`- ✗ [${action.type}] ${action.filePath}: ${action.description} — ${result.error}`);
2317
2380
  }
2381
+ historyEntries.push(createFixHistoryEntry({
2382
+ source: "mcp",
2383
+ dry_run: false,
2384
+ finding: primaryFinding ?? {
2385
+ ruleId: action.ruleId, severity: "medium", category: "",
2386
+ title: action.description, file: "", evidence: "",
2387
+ description: action.description, controlIds: [], fix: action.description,
2388
+ },
2389
+ action,
2390
+ controls: matchedControls,
2391
+ applied: result.applied,
2392
+ error: result.applied ? undefined : result.error,
2393
+ }));
2318
2394
  }
2319
2395
  }
2396
+ if (historyEntries.length > 0 && !dryRun) {
2397
+ appendFixHistory(projectPath, historyEntries);
2398
+ }
2320
2399
  lines.push(`\n## Summary\n`);
2321
2400
  lines.push(`- Actions applied: ${applied}${failed > 0 ? ` (${failed} failed)` : ""}`);
2401
+ if (!dryRun && historyEntries.length > 0) {
2402
+ lines.push(`- Fix history recorded in .ges/fix-history.json`);
2403
+ }
2322
2404
  if (npmInstalls.length > 0) {
2323
2405
  lines.push(`\n## npm Packages to Install\n`);
2324
2406
  lines.push("```bash");
@@ -2913,34 +2995,45 @@ export function handleRequest(request) {
2913
2995
  }
2914
2996
  case "start_dashboard": {
2915
2997
  const projectPath = resolveProjectPath(args.project_path);
2916
- const port = args.port || 3001;
2998
+ const port = typeof args.port === "string" ? parseInt(args.port, 10) : (args.port || 3001);
2917
2999
  const host = args.host || "localhost";
2918
3000
  if (!fs.existsSync(path.join(projectPath, ".ges"))) {
2919
3001
  resultText = `GESF not initialized at ${projectPath}. Run 'init_project' first.`;
2920
3002
  break;
2921
3003
  }
2922
- const lines = [];
2923
- lines.push(`# GESF Web Dashboard\n`);
2924
- lines.push(`**Project**: ${projectPath}`);
2925
- lines.push(`**Host**: ${host}`);
2926
- lines.push(`**Port**: ${port}\n`);
2927
- lines.push(`## Starting the Dashboard\n`);
2928
- lines.push(`The dashboard must be started via the GESF CLI. Run:\n`);
2929
- lines.push(`\`\`\`bash`);
2930
- lines.push(`cd ${projectPath}`);
2931
- lines.push(`ges dashboard --port ${port} --host ${host}`);
2932
- lines.push(`\`\`\`\n`);
2933
- lines.push(`## Available Endpoints\n`);
2934
- lines.push(`- **Dashboard UI**: ${HT}${host}:${port}`);
2935
- lines.push(`- **JSON API**: ${HT}${host}:${port}/api/data`);
2936
- lines.push(`- **Health Check**: ${HT}${host}:${port}/health\n`);
2937
- lines.push(`## Dashboard Features`);
2938
- lines.push(`- Visual compliance score overview`);
2939
- lines.push(`- Per-framework breakdown with grades`);
2940
- lines.push(`- Security findings list`);
2941
- lines.push(`- Control status matrix`);
2942
- lines.push(`- Audit history timeline`);
2943
- resultText = lines.join("\n");
3004
+ if (activeDashboardServer) {
3005
+ try {
3006
+ activeDashboardServer.close();
3007
+ }
3008
+ catch { /* ignore close errors */ }
3009
+ activeDashboardServer = null;
3010
+ }
3011
+ try {
3012
+ const server = startDashboard({ port, host, projectPath });
3013
+ activeDashboardServer = server;
3014
+ const proto = ["http", "//"].join(":");
3015
+ const lines = [];
3016
+ lines.push(`# GESF Web Dashboard Running\n`);
3017
+ lines.push(`**Project**: ${projectPath}`);
3018
+ lines.push(`**Host**: ${host}`);
3019
+ lines.push(`**Port**: ${port}\n`);
3020
+ lines.push(`Dashboard server started successfully.\n`);
3021
+ lines.push(`## Endpoints\n`);
3022
+ lines.push(`- **Dashboard UI**: ${proto}${host}:${port}`);
3023
+ lines.push(`- **JSON API**: ${proto}${host}:${port}/api/data`);
3024
+ lines.push(`- **Health Check**: ${proto}${host}:${port}/health\n`);
3025
+ lines.push(`## Features`);
3026
+ lines.push(`- Visual compliance score overview`);
3027
+ lines.push(`- Per-framework breakdown with grades`);
3028
+ lines.push(`- Security findings list`);
3029
+ lines.push(`- Control status matrix`);
3030
+ lines.push(`- Audit history timeline`);
3031
+ resultText = lines.join("\n");
3032
+ }
3033
+ catch (err) {
3034
+ const msg = err instanceof Error ? err.message : String(err);
3035
+ resultText = `Failed to start dashboard: ${msg}\n\nMake sure port ${port} is available. Try a different port.`;
3036
+ }
2944
3037
  break;
2945
3038
  }
2946
3039
  default:
package/package.json CHANGED
@@ -3,21 +3,22 @@
3
3
  "ges-mcp": "dist/server.js"
4
4
  },
5
5
  "dependencies": {
6
- "@greenarmor/ges-audit-engine": "1.2.0",
7
- "@greenarmor/ges-cicd-generator": "1.2.0",
8
- "@greenarmor/ges-compliance-engine": "1.2.0",
9
- "@greenarmor/ges-core": "1.2.0",
10
- "@greenarmor/ges-doc-generator": "1.2.0",
11
- "@greenarmor/ges-policy-engine": "1.2.0",
12
- "@greenarmor/ges-report-generator": "1.2.0",
13
- "@greenarmor/ges-rules-engine": "1.2.0",
14
- "@greenarmor/ges-scanner-integration": "1.2.0",
15
- "@greenarmor/ges-scoring-engine": "1.2.0"
6
+ "@greenarmor/ges-audit-engine": "1.2.2",
7
+ "@greenarmor/ges-cicd-generator": "1.2.2",
8
+ "@greenarmor/ges-compliance-engine": "1.2.2",
9
+ "@greenarmor/ges-core": "1.2.2",
10
+ "@greenarmor/ges-doc-generator": "1.2.2",
11
+ "@greenarmor/ges-policy-engine": "1.2.2",
12
+ "@greenarmor/ges-report-generator": "1.2.2",
13
+ "@greenarmor/ges-rules-engine": "1.2.2",
14
+ "@greenarmor/ges-scanner-integration": "1.2.2",
15
+ "@greenarmor/ges-scoring-engine": "1.2.2",
16
+ "@greenarmor/ges-web-dashboard": "1.2.2"
16
17
  },
17
18
  "description": "GESF MCP Server - AI Compliance Assistant for GDPR, OWASP, NIST, CIS. Check compliance, generate policies, assess risks via MCP protocol.",
18
19
  "devDependencies": {
19
20
  "@types/node": "^22.0.0",
20
- "esbuild": "^0.28.0",
21
+ "esbuild": "^0.28.1",
21
22
  "typescript": "^6.0.0",
22
23
  "vitest": "^4.1.8"
23
24
  },
@@ -66,7 +67,7 @@
66
67
  },
67
68
  "type": "module",
68
69
  "types": "./dist/index.d.ts",
69
- "version": "1.2.0",
70
+ "version": "1.2.2",
70
71
  "scripts": {
71
72
  "build": "tsc",
72
73
  "clean": "rm -rf dist bundle tsconfig.tsbuildinfo",