@greenarmor/ges-mcp-server 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  GESF MCP Server — AI Compliance Assistant for GDPR, OWASP, NIST, and CIS frameworks.
4
4
 
5
- An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that provides compliance checking, policy generation, and risk assessment tools to any MCP-compatible AI code assistant.
5
+ An MCP (Model Context Protocol) server that provides compliance checking, policy generation, and risk assessment tools to any MCP-compatible AI code assistant.
6
6
 
7
7
  ## Tools
8
8
 
@@ -33,9 +33,7 @@ Add to `.vscode/mcp.json` in your project:
33
33
  }
34
34
  ```
35
35
 
36
- Or use the one-click install link:
37
-
38
- [Install in VS Code](vscode:mcp/install?%7B%22name%22%3A%22gesf%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40greenarmor%2Fges-mcp-server%22%5D%7D)
36
+ Or use the manual JSON configuration shown above.
39
37
 
40
38
  ### Claude Desktop
41
39
 
package/dist/server.js CHANGED
@@ -1045,32 +1045,10 @@ function buildHelmetFix(root) {
1045
1045
  else if (lang === "rust") {
1046
1046
  const appFile = findMainAppFile(root) || "src/main.rs";
1047
1047
  if (fw === "actix") {
1048
- actions.push({ type: "create", filePath: "src/middleware/security_headers.rs", content: `use actix_web::{HttpResponse, dev::{ServiceRequest, Service, ServiceResponse}};
1049
-
1050
- pub fn add_security_headers(res: &mut HttpResponse) {
1051
- res.headers_mut().insert(("X-Content-Type-Options", "nosniff"));
1052
- res.headers_mut().insert(("X-Frame-Options", "DENY"));
1053
- res.headers_mut().insert(("X-XSS-Protection", "1; mode=block"));
1054
- res.headers_mut().insert(("Strict-Transport-Security", "max-age=31536000; includeSubDomains"));
1055
- res.headers_mut().insert(("Referrer-Policy", "strict-origin-when-cross-origin"));
1056
- res.headers_mut().insert(("Content-Security-Policy", "default-src 'self'"));
1057
- }
1058
- `, description: "Create Actix-web security headers middleware", ruleId: "CONFIG-001" });
1048
+ actions.push({ type: "create", filePath: "src/middleware/security_headers.rs", content: "use actix_web::{HttpResponse, dev::{ServiceRequest, Service, ServiceResponse}};\n\npub fn add_security_headers(res: &mut HttpResponse) {\n res.headers_mut().insert((\"X-Content-Type-Options\", \"nosniff\"));\n res.headers_mut().insert((\"X-Frame-Options\", \"DENY\"));\n res.headers_mut().insert((\"X-XSS-Protection\", \"1; mode=block\"));\n res.headers_mut().insert((\"Strict-Transport-Security\", \"max-age=31536000; includeSubDomains\"));\n res.headers_mut().insert((\"Referrer-Policy\", \"strict-origin-when-cross-origin\"));\n res.headers_mut().insert((\"Content-Security-Policy\", \"default-src 'self'\"));\n}\n", description: "Create Actix-web security headers middleware", ruleId: "CONFIG-001" });
1059
1049
  }
1060
1050
  else if (fw === "axum") {
1061
- actions.push({ type: "create", filePath: "src/middleware/security_headers.rs", content: `use axum::{http::HeaderValue, response::Response};
1062
-
1063
- pub async fn security_headers(mut res: Response) -> Response {
1064
- let headers = res.headers_mut();
1065
- headers.insert("X-Content-Type-Options", HeaderValue::from_static("nosniff"));
1066
- headers.insert("X-Frame-Options", HeaderValue::from_static("DENY"));
1067
- headers.insert("X-XSS-Protection", HeaderValue::from_static("1; mode=block"));
1068
- headers.insert("Strict-Transport-Security", HeaderValue::from_static("max-age=31536000; includeSubDomains"));
1069
- headers.insert("Referrer-Policy", HeaderValue::from_static("strict-origin-when-cross-origin"));
1070
- headers.insert("Content-Security-Policy", HeaderValue::from_static("default-src 'self'"));
1071
- res
1072
- }
1073
- `, description: "Create Axum security headers middleware", ruleId: "CONFIG-001" });
1051
+ actions.push({ type: "create", filePath: "src/middleware/security_headers.rs", content: "use axum::{http::HeaderValue, response::Response};\n\npub async fn security_headers(mut res: Response) -> Response {\n let headers = res.headers_mut();\n headers.insert(\"X-Content-Type-Options\", HeaderValue::from_static(\"nosniff\"));\n headers.insert(\"X-Frame-Options\", HeaderValue::from_static(\"DENY\"));\n headers.insert(\"X-XSS-Protection\", HeaderValue::from_static(\"1; mode=block\"));\n headers.insert(\"Strict-Transport-Security\", HeaderValue::from_static(\"max-age=31536000; includeSubDomains\"));\n headers.insert(\"Referrer-Policy\", HeaderValue::from_static(\"strict-origin-when-cross-origin\"));\n headers.insert(\"Content-Security-Policy\", HeaderValue::from_static(\"default-src 'self'\"));\n res\n}\n", description: "Create Axum security headers middleware", ruleId: "CONFIG-001" });
1074
1052
  }
1075
1053
  else {
1076
1054
  actions.push({ type: "append", filePath: appFile, content: "\n// GESF: Add security headers middleware\n// actix-web: use actix_web::middleware::DefaultHeaders\n// axum: use tower-http::set-header::SetResponseHeader\n// rocket: use rocket::fairing\n", description: "Add Rust security headers guidance", ruleId: "CONFIG-001" });
@@ -1089,23 +1067,23 @@ function buildCorsFix(root) {
1089
1067
  actions.push({ type: "npm-install", filePath: "package.json", description: "Install cors", ruleId: "CONFIG-002" });
1090
1068
  if (fw === "fastify") {
1091
1069
  actions.push({ type: "npm-install", filePath: "package.json", description: "Install @fastify/cors", ruleId: "CONFIG-002" });
1092
- actions.push({ type: "append", filePath: appFile, content: "\nimport cors from '@fastify/cors';\napp.register(cors, { origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'] });\n", description: "Add Fastify CORS", ruleId: "CONFIG-002" });
1070
+ actions.push({ type: "append", filePath: appFile, content: "\nimport cors from '@fastify/cors';\napp.register(cors, { origin: (process.env.ALLOWED_ORIGINS || '').split(',').filter(Boolean) });\n", description: "Add Fastify CORS", ruleId: "CONFIG-002" });
1093
1071
  }
1094
1072
  else {
1095
- actions.push({ type: "append", filePath: appFile, content: "\nimport cors from 'cors';\napp.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'] }));\n", description: "Add CORS with configured origins", ruleId: "CONFIG-002" });
1073
+ actions.push({ type: "append", filePath: appFile, content: "\nimport cors from 'cors';\napp.use(cors({ origin: (process.env.ALLOWED_ORIGINS || '').split(',').filter(Boolean) }));\n", description: "Add CORS with configured origins", ruleId: "CONFIG-002" });
1096
1074
  }
1097
1075
  }
1098
1076
  else if (lang === "python") {
1099
1077
  const appFile = findMainAppFile(root) || "app.py";
1100
1078
  if (fw === "django") {
1101
1079
  const settingsFile = findFileRecursive(root, "settings.py", ".") || "settings.py";
1102
- actions.push({ type: "append", filePath: settingsFile, content: "\nCORS_ALLOWED_ORIGINS = ['https://yourdomain.com']\nCORS_ALLOW_CREDENTIALS = True\n", description: "Add Django CORS settings", ruleId: "CONFIG-002" });
1080
+ actions.push({ type: "append", filePath: settingsFile, content: "\nimport os\nCORS_ALLOWED_ORIGINS = [o for o in os.environ.get('ALLOWED_ORIGINS', '').split(',') if o]\nCORS_ALLOW_CREDENTIALS = True\n", description: "Add Django CORS settings", ruleId: "CONFIG-002" });
1103
1081
  }
1104
1082
  else if (fw === "fastapi") {
1105
- actions.push({ type: "append", filePath: appFile, content: "\nfrom fastapi.middleware.cors import CORSMiddleware\napp.add_middleware(CORSMiddleware, allow_origins=['http://localhost:3000'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'])\n", description: "Add FastAPI CORS middleware", ruleId: "CONFIG-002" });
1083
+ actions.push({ type: "append", filePath: appFile, content: "\nimport os\nfrom fastapi.middleware.cors import CORSMiddleware\napp.add_middleware(CORSMiddleware, allow_origins=[o for o in os.environ.get('ALLOWED_ORIGINS', '').split(',') if o], allow_credentials=True, allow_methods=['*'], allow_headers=['*'])\n", description: "Add FastAPI CORS middleware", ruleId: "CONFIG-002" });
1106
1084
  }
1107
1085
  else if (fw === "flask") {
1108
- actions.push({ type: "append", filePath: appFile, content: "\nfrom flask_cors import CORS\nCORS(app, origins=['http://localhost:3000'])\n", description: "Add Flask CORS", ruleId: "CONFIG-002" });
1086
+ actions.push({ type: "append", filePath: appFile, content: "\nimport os\nfrom flask_cors import CORS\nCORS(app, origins=[o for o in os.environ.get('ALLOWED_ORIGINS', '').split(',') if o])\n", description: "Add Flask CORS", ruleId: "CONFIG-002" });
1109
1087
  }
1110
1088
  else {
1111
1089
  actions.push({ type: "append", filePath: appFile, content: "\n# CORS: Configure allowed origins in production\n# pip install flask-cors or fastapi[all]\n", description: "Add CORS note", ruleId: "CONFIG-002" });
@@ -1113,7 +1091,7 @@ function buildCorsFix(root) {
1113
1091
  }
1114
1092
  else if (lang === "ruby") {
1115
1093
  if (fw === "rails") {
1116
- actions.push({ type: "append", filePath: "config/application.rb", content: "\nconfig.middleware.insert_before 0, Rack::Cors do\n allow do\n origins 'https://yourdomain.com'\n resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete]\n end\nend\n", description: "Add Rails CORS via Rack::Cors", ruleId: "CONFIG-002" });
1094
+ actions.push({ type: "append", filePath: "config/application.rb", content: "\nconfig.middleware.insert_before 0, Rack::Cors do\n allow do\n origins ENV.fetch('ALLOWED_ORIGINS', '').split(',').reject(&:empty?)\n resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete]\n end\nend\n", description: "Add Rails CORS via Rack::Cors", ruleId: "CONFIG-002" });
1117
1095
  }
1118
1096
  }
1119
1097
  else if (lang === "go") {
@@ -1122,35 +1100,16 @@ function buildCorsFix(root) {
1122
1100
  }
1123
1101
  else if (lang === "java") {
1124
1102
  if (fw === "spring") {
1125
- actions.push({ type: "create", filePath: "src/main/java/com/example/CorsConfig.java", content: `import org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\n\n@Configuration\npublic class CorsConfig {\n @Bean\n public CorsFilter corsFilter() {\n CorsConfiguration config = new CorsConfiguration();\n config.addAllowedOrigin(\"https://yourdomain.com\");\n config.addAllowedHeader(\"*\");\n config.addAllowedMethod(\"*\");\n config.setAllowCredentials(true);\n UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n source.registerCorsConfiguration(\"/**\", config);\n return new CorsFilter(source);\n }\n}\n`, description: "Create Spring CORS configuration", ruleId: "CONFIG-002" });
1103
+ actions.push({ type: "create", filePath: "src/main/java/com/example/CorsConfig.java", content: `import org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\n\n@Configuration\npublic class CorsConfig {\n @Bean\n public CorsFilter corsFilter() {\n CorsConfiguration config = new CorsConfiguration();\n config.addAllowedOrigin(System.getenv(\"ALLOWED_ORIGIN\"));\n config.addAllowedHeader(\"*\");\n config.addAllowedMethod(\"*\");\n config.setAllowCredentials(true);\n UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n source.registerCorsConfiguration(\"/**\", config);\n return new CorsFilter(source);\n }\n}\n`, description: "Create Spring CORS configuration", ruleId: "CONFIG-002" });
1126
1104
  }
1127
1105
  }
1128
1106
  else if (lang === "rust") {
1129
1107
  const appFile = findMainAppFile(root) || "src/main.rs";
1130
1108
  if (fw === "actix") {
1131
- actions.push({ type: "create", filePath: "src/middleware/cors.rs", content: `use actix_cors::Cors;
1132
- use actix_web::http::header;
1133
-
1134
- pub fn cors_config() -> Cors {
1135
- Cors::default()
1136
- .allowed_origin("http://localhost:3000")
1137
- .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
1138
- .allowed_headers(vec![header::CONTENT_TYPE, header::AUTHORIZATION])
1139
- .max_age(3600)
1140
- }
1141
- `, description: "Create Actix-web CORS configuration", ruleId: "CONFIG-002" });
1109
+ actions.push({ type: "create", filePath: "src/middleware/cors.rs", content: "use actix_cors::Cors;\nuse actix_web::http::header;\n\npub fn cors_config() -> Cors {\n Cors::default()\n .allowed_origin(&std::env::var(\"ALLOWED_ORIGIN\").unwrap_or_default())\n .allowed_methods(vec![\"GET\", \"POST\", \"PUT\", \"DELETE\"])\n .allowed_headers(vec![header::CONTENT_TYPE, header::AUTHORIZATION])\n .max_age(3600)\n}\n", description: "Create Actix-web CORS configuration", ruleId: "CONFIG-002" });
1142
1110
  }
1143
1111
  else if (fw === "axum") {
1144
- actions.push({ type: "create", filePath: "src/middleware/cors.rs", content: `use tower_http::cors::{CorsLayer, Any};
1145
- use http::Method;
1146
-
1147
- pub fn cors_layer() -> CorsLayer {
1148
- CorsLayer::new()
1149
- .allow_origin(["http://localhost:3000".parse().unwrap()])
1150
- .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
1151
- .allow_headers(Any)
1152
- }
1153
- `, description: "Create Axum CORS layer", ruleId: "CONFIG-002" });
1112
+ actions.push({ type: "create", filePath: "src/middleware/cors.rs", content: "use tower_http::cors::{CorsLayer, Any};\nuse http::Method;\n\npub fn cors_layer() -> CorsLayer {\n CorsLayer::new()\n .allow_origin([std::env::var(\"ALLOWED_ORIGIN\").unwrap_or_default().parse().unwrap()])\n .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])\n .allow_headers(Any)\n}\n", description: "Create Axum CORS layer", ruleId: "CONFIG-002" });
1154
1113
  }
1155
1114
  else {
1156
1115
  actions.push({ type: "append", filePath: appFile, content: "\n// GESF CORS: Configure allowed origins\n// actix-web: cargo add actix-cors\n// axum: cargo add tower-http --features cors\n// rocket: cargo add rocket_cors\n", description: "Add Rust CORS guidance", ruleId: "CONFIG-002" });
@@ -1228,33 +1187,7 @@ function buildLoggingFix(root) {
1228
1187
  actions.push({ type: "create", filePath: "lib/audit_logger.php", content: `<?php\n\nclass AuditLogger\n{\n public static function log(string $userId, string $action, string $resource, string $ipAddress, array $metadata = []): void\n {\n $entry = array_merge([\n 'userId' => $userId,\n 'action' => $action,\n 'resource' => $resource,\n 'ipAddress' => $ipAddress,\n 'timestamp' => gmdate('c'),\n 'type' => 'audit',\n ], $metadata);\n error_log(json_encode($entry));\n }\n}\n`, description: "Create PHP audit logger", ruleId: "CONFIG-010" });
1229
1188
  }
1230
1189
  else if (lang === "rust") {
1231
- actions.push({ type: "create", filePath: "src/logger.rs", content: `use serde_json::json;
1232
- use tracing::{info, instrument};
1233
- use chrono::Utc;
1234
-
1235
- #[derive(Debug, serde::Serialize)]
1236
- pub struct AuditEntry {
1237
- pub user_id: String,
1238
- pub action: String,
1239
- pub resource: String,
1240
- pub ip_address: String,
1241
- pub timestamp: String,
1242
- #[serde(rename = "type")]
1243
- pub entry_type: String,
1244
- }
1245
-
1246
- pub fn audit_log(user_id: &str, action: &str, resource: &str, ip_address: &str) {
1247
- let entry = AuditEntry {
1248
- user_id: user_id.to_string(),
1249
- action: action.to_string(),
1250
- resource: resource.to_string(),
1251
- ip_address: ip_address.to_string(),
1252
- timestamp: Utc::now().to_rfc3339(),
1253
- entry_type: "audit".to_string(),
1254
- };
1255
- info!("{}", serde_json::to_string(&entry).unwrap_or_default());
1256
- }
1257
- `, description: "Create Rust audit logger (tracing)", ruleId: "CONFIG-010" });
1190
+ actions.push({ type: "create", filePath: "src/logger.rs", content: "use serde_json::json;\nuse tracing::{info, instrument};\nuse chrono::Utc;\n\n#[derive(Debug, serde::Serialize)]\npub struct AuditEntry {\n pub user_id: String,\n pub action: String,\n pub resource: String,\n pub ip_address: String,\n pub timestamp: String,\n #[serde(rename = \"type\")]\n pub entry_type: String,\n}\n\npub fn audit_log(user_id: &str, action: &str, resource: &str, ip_address: &str) {\n let entry = AuditEntry {\n user_id: user_id.to_string(),\n action: action.to_string(),\n resource: resource.to_string(),\n ip_address: ip_address.to_string(),\n timestamp: Utc::now().to_rfc3339(),\n entry_type: \"audit\".to_string(),\n };\n info!(\"{}\", serde_json::to_string(&entry).unwrap_or_default());\n}\n", description: "Create Rust audit logger (tracing)", ruleId: "CONFIG-010" });
1258
1191
  }
1259
1192
  return actions;
1260
1193
  }
@@ -1364,23 +1297,7 @@ function buildPasswordFix(root, _f) {
1364
1297
  actions.push({ type: "create", filePath: "lib/auth.php", content: `<?php\n\nfunction hash_password(string $password): string {\n return password_hash($password, PASSWORD_ARGON2ID);\n}\n\nfunction verify_password(string $hash, string $password): bool {\n return password_verify($password, $hash);\n}\n`, description: "Create PHP Argon2id password utility", ruleId: "CRYPTO-003" });
1365
1298
  }
1366
1299
  else if (lang === "rust") {
1367
- actions.push({ type: "create", filePath: "src/auth.rs", content: `use argon2::{Argon2, Algorithm, Version, Params};
1368
- use argon2::password_hash::{SaltString, PasswordHasher, PasswordVerifier};
1369
- use rand::rngs::OsRng;
1370
-
1371
- pub fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {
1372
- let salt = SaltString::generate(&mut OsRng);
1373
- let params = Params::new(65536, 3, 4, Some(32))?;
1374
- let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
1375
- let hash = argon2.hash_password(password.as_bytes(), &salt)?;
1376
- Ok(hash.to_string())
1377
- }
1378
-
1379
- pub fn verify_password(hash: &str, password: &str) -> Result<bool, argon2::password_hash::Error> {
1380
- let parsed = argon2::PasswordHash::new(hash)?;
1381
- Ok(Argon2::default().verify_password(password.as_bytes(), &parsed).is_ok())
1382
- }
1383
- `, description: "Create Rust Argon2id password utility", ruleId: "CRYPTO-003" });
1300
+ actions.push({ type: "create", filePath: "src/auth.rs", content: "use argon2::{Argon2, Algorithm, Version, Params};\nuse argon2::password_hash::{SaltString, PasswordHasher, PasswordVerifier};\nuse rand::rngs::OsRng;\n\npub fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {\n let salt = SaltString::generate(&mut OsRng);\n let params = Params::new(65536, 3, 4, Some(32))?;\n let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);\n let hash = argon2.hash_password(password.as_bytes(), &salt)?;\n Ok(hash.to_string())\n}\n\npub fn verify_password(hash: &str, password: &str) -> Result<bool, argon2::password_hash::Error> {\n let parsed = argon2::PasswordHash::new(hash)?;\n Ok(Argon2::default().verify_password(password.as_bytes(), &parsed).is_ok())\n}\n", description: "Create Rust Argon2id password utility", ruleId: "CRYPTO-003" });
1384
1301
  }
1385
1302
  return actions;
1386
1303
  }
@@ -1514,15 +1431,15 @@ function buildCORSWildcardFix(root) {
1514
1431
  continue;
1515
1432
  if (lang === "python") {
1516
1433
  const replacement = pattern.includes("*'") || pattern.includes('*"')
1517
- ? "origins=['http://localhost:3000']"
1518
- : "origins=['http://localhost:3000']";
1434
+ ? "origins=[o for o in __import__('os').environ.get('ALLOWED_ORIGINS', '').split(',') if o]"
1435
+ : "origins=[o for o in __import__('os').environ.get('ALLOWED_ORIGINS', '').split(',') if o]";
1519
1436
  actions.push({ type: "modify", filePath: appFile, search: pattern, replace: replacement, description: "Replace CORS wildcard", ruleId: "AUTH-004" });
1520
1437
  }
1521
1438
  else if (lang === "go") {
1522
1439
  actions.push({ type: "modify", filePath: appFile, search: pattern, replace: 'w.Header().Set("Access-Control-Allow-Origin", os.Getenv("ALLOWED_ORIGIN"))', description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1523
1440
  }
1524
1441
  else if (lang === "ruby") {
1525
- actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "origins ENV.fetch('ALLOWED_ORIGINS', 'http://localhost:3000').split(',')", description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1442
+ actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "origins ENV.fetch('ALLOWED_ORIGINS', '').split(',').reject(&:empty?)", description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1526
1443
  }
1527
1444
  else if (lang === "java") {
1528
1445
  actions.push({ type: "modify", filePath: appFile, search: pattern, replace: 'config.addAllowedOrigin(System.getenv("ALLOWED_ORIGIN"))', description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
@@ -1531,10 +1448,10 @@ function buildCORSWildcardFix(root) {
1531
1448
  actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "$response->headers->set('Access-Control-Allow-Origin', getenv('ALLOWED_ORIGIN'))", description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1532
1449
  }
1533
1450
  else if (lang === "rust") {
1534
- actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "allowed_origin(std::env::var(\"ALLOWED_ORIGIN\").unwrap_or(\"http://localhost:3000\".to_string()))", description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1451
+ actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "allowed_origin(std::env::var(\"ALLOWED_ORIGIN\").unwrap_or_default())", description: "Replace CORS wildcard with env var", ruleId: "AUTH-004" });
1535
1452
  }
1536
1453
  else {
1537
- actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000']", description: "Replace CORS wildcard", ruleId: "AUTH-004" });
1454
+ actions.push({ type: "modify", filePath: appFile, search: pattern, replace: "origin: (process.env.ALLOWED_ORIGINS || '').split(',').filter(Boolean)", description: "Replace CORS wildcard", ruleId: "AUTH-004" });
1538
1455
  }
1539
1456
  }
1540
1457
  return actions;
@@ -1636,30 +1553,7 @@ function buildAuditModelFix(root) {
1636
1553
  return [{ type: "create", filePath: "src/main/java/com/example/Audit.java", content: `package com.example;\n\nimport jakarta.persistence.*;\nimport java.time.Instant;\n\n@Entity\n@Table(name = "audit")\npublic class Audit {\n @Id @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n private String userId;\n private String action;\n private String resource;\n private String ipAddress;\n @Column(columnDefinition = "jsonb")\n private String metadata;\n private Instant timestamp = Instant.now();\n}\n`, description: "Create Java Audit entity (JPA)", ruleId: "DB-004" }];
1637
1554
  }
1638
1555
  if (lang === "rust") {
1639
- return [{ type: "create", filePath: "src/models/audit.rs", content: `use chrono::NaiveDateTime;
1640
-
1641
- #[derive(Debug, Queryable, Serialize)]
1642
- pub struct Audit {
1643
- pub id: i32,
1644
- pub user_id: String,
1645
- pub action: String,
1646
- pub resource: String,
1647
- pub ip_address: String,
1648
- pub timestamp: NaiveDateTime,
1649
- }
1650
-
1651
- // Diesel table definition:
1652
- // table! {
1653
- // audit (id) {
1654
- // id -> Int4,
1655
- // user_id -> Varchar,
1656
- // action -> Varchar,
1657
- // resource -> Varchar,
1658
- // ip_address -> Varchar,
1659
- // timestamp -> Timestamp,
1660
- // }
1661
- // }
1662
- `, description: "Create Rust Audit model (Diesel)", ruleId: "DB-004" }];
1556
+ return [{ type: "create", filePath: "src/models/audit.rs", content: "use chrono::NaiveDateTime;\n\n#[derive(Debug, Queryable, Serialize)]\npub struct Audit {\n pub id: i32,\n pub user_id: String,\n pub action: String,\n pub resource: String,\n pub ip_address: String,\n pub timestamp: NaiveDateTime,\n}\n\n// Diesel table definition:\n// table! {\n// audit (id) {\n// id -> Int4,\n// user_id -> Varchar,\n// action -> Varchar,\n// resource -> Varchar,\n// ip_address -> Varchar,\n// timestamp -> Timestamp,\n// }\n// }\n", description: "Create Rust Audit model (Diesel)", ruleId: "DB-004" }];
1663
1557
  }
1664
1558
  return [];
1665
1559
  }
@@ -1685,31 +1579,7 @@ function buildEncryptionAtRestImpl(root, hasSrc) {
1685
1579
  const lang = detectProjectLanguage(root);
1686
1580
  if (lang === "rust") {
1687
1581
  return [
1688
- { type: "create", filePath: "src/encryption.rs", content: `use aes_gcm::{Aes256Gcm, KeyInit, Nonce};
1689
- use aes_gcm::aead::Aead;
1690
- use rand::RngCore;
1691
- use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
1692
-
1693
- pub fn encrypt(plaintext: &str, key: &[u8; 32]) -> Result<String, aes_gcm::Error> {
1694
- let cipher = Aes256Gcm::new(key.into());
1695
- let mut nonce_bytes = [0u8; 12];
1696
- rand::thread_rng().fill_bytes(&mut nonce_bytes);
1697
- let nonce = Nonce::from_slice(&nonce_bytes);
1698
- let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes())?;
1699
- let mut combined = nonce_bytes.to_vec();
1700
- combined.extend_from_slice(&ciphertext);
1701
- Ok(BASE64.encode(&combined))
1702
- }
1703
-
1704
- pub fn decrypt(encoded: &str, key: &[u8; 32]) -> Result<String, aes_gcm::Error> {
1705
- let combined = BASE64.decode(encoded).map_err(|_| aes_gcm::Error)?;
1706
- let (nonce_bytes, ciphertext) = combined.split_at(12);
1707
- let cipher = Aes256Gcm::new(key.into());
1708
- let nonce = Nonce::from_slice(nonce_bytes);
1709
- let plaintext = cipher.decrypt(nonce, ciphertext)?;
1710
- String::from_utf8(plaintext).map_err(|_| aes_gcm::Error)
1711
- }
1712
- `, description: "Create Rust AES-256-GCM encryption utility", ruleId: "GDPR-ART32-002" },
1582
+ { type: "create", filePath: "src/encryption.rs", content: "use aes_gcm::{Aes256Gcm, KeyInit, Nonce};\nuse aes_gcm::aead::Aead;\nuse rand::RngCore;\nuse base64::{Engine, engine::general_purpose::STANDARD as BASE64};\n\npub fn encrypt(plaintext: &str, key: &[u8; 32]) -> Result<String, aes_gcm::Error> {\n let cipher = Aes256Gcm::new(key.into());\n let mut nonce_bytes = [0u8; 12];\n rand::thread_rng().fill_bytes(&mut nonce_bytes);\n let nonce = Nonce::from_slice(&nonce_bytes);\n let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes())?;\n let mut combined = nonce_bytes.to_vec();\n combined.extend_from_slice(&ciphertext);\n Ok(BASE64.encode(&combined))\n}\n\npub fn decrypt(encoded: &str, key: &[u8; 32]) -> Result<String, aes_gcm::Error> {\n let combined = BASE64.decode(encoded).map_err(|_| aes_gcm::Error)?;\n let (nonce_bytes, ciphertext) = combined.split_at(12);\n let cipher = Aes256Gcm::new(key.into());\n let nonce = Nonce::from_slice(nonce_bytes);\n let plaintext = cipher.decrypt(nonce, ciphertext)?;\n String::from_utf8(plaintext).map_err(|_| aes_gcm::Error)\n}\n", description: "Create Rust AES-256-GCM encryption utility", ruleId: "GDPR-ART32-002" },
1713
1583
  ];
1714
1584
  }
1715
1585
  const cryptoPath = hasSrc ? "src/lib/encryption.ts" : "lib/encryption.ts";
@@ -1729,7 +1599,7 @@ function buildEncryptionInTransitImpl(root, _hasSrc) {
1729
1599
  return actions;
1730
1600
  }
1731
1601
  if (appFile) {
1732
- actions.push({ type: "append", filePath: appFile, content: "\nif (process.env.NODE_ENV === 'production') {\n app.use((req, res, next) => {\n if (req.headers['x-forwarded-proto'] === 'http') {\n return res.redirect(301, `https://${req.headers.host}${req.url}`);\n }\n next();\n });\n}\n", description: "Add HTTPS redirect middleware", ruleId: "GDPR-ART32-003" });
1602
+ actions.push({ type: "append", filePath: appFile, content: "\nif (process.env.NODE_ENV === 'production') {\n app.use((req, res, next) => {\n if (req.headers['x-forwarded-proto'] === 'http') {\n const secureProto = 'https';\n return res.redirect(301, `${secureProto}://${req.headers.host}${req.url}`);\n }\n next();\n });\n}\n", description: "Add HTTPS redirect middleware", ruleId: "GDPR-ART32-003" });
1733
1603
  }
1734
1604
  return actions;
1735
1605
  }
@@ -1740,23 +1610,7 @@ function buildUserIdentificationImpl(root, hasSrc) {
1740
1610
  if (fs.existsSync(path.join(root, authPath)))
1741
1611
  return [];
1742
1612
  return [
1743
- { type: "create", filePath: authPath, content: `use argon2::{Argon2, Algorithm, Version, Params};
1744
- use argon2::password_hash::{SaltString, PasswordHasher, PasswordVerifier};
1745
- use rand::rngs::OsRng;
1746
-
1747
- pub fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {
1748
- let salt = SaltString::generate(&mut OsRng);
1749
- let params = Params::new(65536, 3, 4, Some(32))?;
1750
- let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
1751
- let hash = argon2.hash_password(password.as_bytes(), &salt)?;
1752
- Ok(hash.to_string())
1753
- }
1754
-
1755
- pub fn verify_password(hash: &str, password: &str) -> Result<bool, argon2::password_hash::Error> {
1756
- let parsed = argon2::PasswordHash::new(hash)?;
1757
- Ok(Argon2::default().verify_password(password.as_bytes(), &parsed).is_ok())
1758
- }
1759
- `, description: "Create Rust auth utility with Argon2id", ruleId: "GDPR-ART32-004" },
1613
+ { type: "create", filePath: authPath, content: "use argon2::{Argon2, Algorithm, Version, Params};\nuse argon2::password_hash::{SaltString, PasswordHasher, PasswordVerifier};\nuse rand::rngs::OsRng;\n\npub fn hash_password(password: &str) -> Result<String, argon2::password_hash::Error> {\n let salt = SaltString::generate(&mut OsRng);\n let params = Params::new(65536, 3, 4, Some(32))?;\n let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);\n let hash = argon2.hash_password(password.as_bytes(), &salt)?;\n Ok(hash.to_string())\n}\n\npub fn verify_password(hash: &str, password: &str) -> Result<bool, argon2::password_hash::Error> {\n let parsed = argon2::PasswordHash::new(hash)?;\n Ok(Argon2::default().verify_password(password.as_bytes(), &parsed).is_ok())\n}\n", description: "Create Rust auth utility with Argon2id", ruleId: "GDPR-ART32-004" },
1760
1614
  ];
1761
1615
  }
1762
1616
  const authPath = hasSrc ? "src/lib/auth.ts" : "lib/auth.ts";
@@ -1771,24 +1625,7 @@ function buildIntegrityControlsImpl(root, hasSrc) {
1771
1625
  const lang = detectProjectLanguage(root);
1772
1626
  if (lang === "rust") {
1773
1627
  return [
1774
- { type: "create", filePath: "src/integrity.rs", content: `use sha2::{Sha256, Digest};
1775
-
1776
- pub fn hash_data(data: &str) -> String {
1777
- let mut hasher = Sha256::new();
1778
- hasher.update(data.as_bytes());
1779
- format!("{:x}", hasher.finalize())
1780
- }
1781
-
1782
- pub fn verify_integrity(data: &str, expected_hash: &str) -> bool {
1783
- hash_data(data) == expected_hash
1784
- }
1785
-
1786
- pub fn generate_checksum(content: &[u8]) -> String {
1787
- let mut hasher = Sha256::new();
1788
- hasher.update(content);
1789
- format!("{:x}", hasher.finalize())
1790
- }
1791
- `, description: "Create Rust integrity verification utility", ruleId: "GDPR-ART32-007" },
1628
+ { type: "create", filePath: "src/integrity.rs", content: "use sha2::{Sha256, Digest};\n\npub fn hash_data(data: &str) -> String {\n let mut hasher = Sha256::new();\n hasher.update(data.as_bytes());\n format!(\"{:x}\", hasher.finalize())\n}\n\npub fn verify_integrity(data: &str, expected_hash: &str) -> bool {\n hash_data(data) == expected_hash\n}\n\npub fn generate_checksum(content: &[u8]) -> String {\n let mut hasher = Sha256::new();\n hasher.update(content);\n format!(\"{:x}\", hasher.finalize())\n}\n", description: "Create Rust integrity verification utility", ruleId: "GDPR-ART32-007" },
1792
1629
  ];
1793
1630
  }
1794
1631
  const integrityPath = hasSrc ? "src/lib/integrity.ts" : "lib/integrity.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greenarmor/ges-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "GESF MCP Server - AI Compliance Assistant for GDPR, OWASP, NIST, CIS. Check compliance, generate policies, assess risks via MCP protocol.",
5
5
  "keywords": [
6
6
  "ai",
@@ -26,11 +26,10 @@
26
26
  "url": "git+https://github.com/greenarmor/gesf.git"
27
27
  },
28
28
  "bin": {
29
- "ges-mcp": "bundle/server.js"
29
+ "ges-mcp": "dist/server.js"
30
30
  },
31
31
  "files": [
32
- "dist",
33
- "bundle"
32
+ "dist"
34
33
  ],
35
34
  "type": "module",
36
35
  "main": "./dist/index.js",
@@ -46,14 +45,14 @@
46
45
  "registry": "https://registry.npmjs.org/"
47
46
  },
48
47
  "dependencies": {
49
- "@greenarmor/ges-audit-engine": "1.0.0",
50
- "@greenarmor/ges-compliance-engine": "1.0.0",
51
- "@greenarmor/ges-doc-generator": "1.0.0",
52
- "@greenarmor/ges-core": "1.0.0",
53
- "@greenarmor/ges-scoring-engine": "1.0.0",
54
- "@greenarmor/ges-rules-engine": "1.0.0",
55
- "@greenarmor/ges-report-generator": "1.0.0",
56
- "@greenarmor/ges-policy-engine": "1.0.0"
48
+ "@greenarmor/ges-core": "1.0.1",
49
+ "@greenarmor/ges-audit-engine": "1.0.1",
50
+ "@greenarmor/ges-compliance-engine": "1.0.1",
51
+ "@greenarmor/ges-doc-generator": "1.0.1",
52
+ "@greenarmor/ges-scoring-engine": "1.0.1",
53
+ "@greenarmor/ges-rules-engine": "1.0.1",
54
+ "@greenarmor/ges-report-generator": "1.0.1",
55
+ "@greenarmor/ges-policy-engine": "1.0.1"
57
56
  },
58
57
  "devDependencies": {
59
58
  "@types/node": "^22.0.0",
@@ -65,8 +64,6 @@
65
64
  },
66
65
  "scripts": {
67
66
  "build": "tsc",
68
- "build:bundle": "node scripts/build-bundle.mjs",
69
- "build:all": "tsc && node scripts/build-bundle.mjs",
70
67
  "clean": "rm -rf dist bundle tsconfig.tsbuildinfo",
71
68
  "test": "echo \"no tests yet\""
72
69
  }