@aaa-sentinel/mcp-server 0.6.0 → 0.8.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.
Files changed (3) hide show
  1. package/README.md +3 -1
  2. package/dist/cli.js +129 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -109,9 +109,11 @@ status as plain JSON.
109
109
  | `list_cost_anomalies` | `accountId?` | `reports:read` | Business |
110
110
  | `get_security_overview` | — | `security:read` | Pro + security add-on |
111
111
  | `get_security_score` | `accountId` | `security:read` | Pro + security add-on |
112
- | `list_security_findings` | `accountId`, `source?` | `security:read` | Pro + security add-on |
112
+ | `list_security_findings` | `accountId`, `source?`, `category?` | `security:read` | Pro + security add-on |
113
113
  | `get_security_critical_changes` | `accountId` | `security:read` | Pro + security add-on |
114
+ | `list_security_vulnerabilities` | `accountId` | `security:read` | Pro + security add-on |
114
115
  | `get_security_conformance` | `accountId` or `clientId` | `security:read` | Pro + security add-on |
116
+ | `get_security_posture_history` | `accountId` or `clientId`, `days?` | `security:read` | Pro + security add-on |
115
117
  | `get_account` | `accountId` | `accounts:read` | Pro |
116
118
  | `get_account_monthly_costs` | `accountId` | `accounts:read` | Pro |
117
119
  | `get_cost_history` | `accountId` | `reports:read` | Pro |
package/dist/cli.js CHANGED
@@ -2800,6 +2800,28 @@ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
2800
2800
  return payload;
2801
2801
  };
2802
2802
  });
2803
+ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
2804
+ $ZodType.init(inst, def);
2805
+ const values = new Set(def.values);
2806
+ inst._zod.values = values;
2807
+ defineLazyInternal(inst, "pattern", (zod) => {
2808
+ const vals = zod.def.values;
2809
+ return new RegExp(vals.length ? `^(${vals.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$` : "^[^\\s\\S]$");
2810
+ });
2811
+ inst._zod.parse = (payload, _ctx) => {
2812
+ const input = payload.value;
2813
+ if (values.has(input)) {
2814
+ return payload;
2815
+ }
2816
+ payload.issues.push({
2817
+ code: "invalid_value",
2818
+ values: def.values,
2819
+ input,
2820
+ inst
2821
+ });
2822
+ return payload;
2823
+ };
2824
+ });
2803
2825
  var $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def) => {
2804
2826
  $ZodType.init(inst, def);
2805
2827
  inst._zod.optin = "optional";
@@ -4739,6 +4761,46 @@ var enumProcessor = (schema, _ctx, json, _params) => {
4739
4761
  json.type = "string";
4740
4762
  json.enum = values;
4741
4763
  };
4764
+ var literalProcessor = (schema, ctx, json, params) => {
4765
+ const def = schema._zod.def;
4766
+ if (def.values.length === 0) {
4767
+ json.not = {};
4768
+ return;
4769
+ }
4770
+ const vals = [];
4771
+ for (const val of def.values) {
4772
+ if (val === void 0) {
4773
+ if (handleUnrepresentable(schema, ctx, json, params, "Literal `undefined` cannot be represented in JSON Schema"))
4774
+ return;
4775
+ } else if (typeof val === "bigint") {
4776
+ if (handleUnrepresentable(schema, ctx, json, params, "BigInt literals cannot be represented in JSON Schema"))
4777
+ return;
4778
+ vals.push(Number(val));
4779
+ } else {
4780
+ vals.push(val);
4781
+ }
4782
+ }
4783
+ if (vals.length === 0) {
4784
+ } else if (vals.length === 1) {
4785
+ const val = vals[0];
4786
+ json.type = val === null ? "null" : typeof val;
4787
+ if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
4788
+ json.enum = [val];
4789
+ } else {
4790
+ json.const = val;
4791
+ }
4792
+ } else {
4793
+ if (vals.every((v) => typeof v === "number"))
4794
+ json.type = "number";
4795
+ if (vals.every((v) => typeof v === "string"))
4796
+ json.type = "string";
4797
+ if (vals.every((v) => typeof v === "boolean"))
4798
+ json.type = "boolean";
4799
+ if (vals.every((v) => v === null))
4800
+ json.type = "null";
4801
+ json.enum = vals;
4802
+ }
4803
+ };
4742
4804
  var customProcessor = (schema, ctx, json, params) => {
4743
4805
  handleUnrepresentable(schema, ctx, json, params, "Custom types cannot be represented in JSON Schema");
4744
4806
  };
@@ -5668,6 +5730,27 @@ function _enum(values, params) {
5668
5730
  ...util_exports.normalizeParams(params)
5669
5731
  });
5670
5732
  }
5733
+ var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
5734
+ $ZodLiteral.init(inst, def);
5735
+ ZodType.init(inst, def);
5736
+ inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params);
5737
+ inst.values = new Set(def.values);
5738
+ Object.defineProperty(inst, "value", {
5739
+ get() {
5740
+ if (def.values.length > 1) {
5741
+ throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");
5742
+ }
5743
+ return def.values[0];
5744
+ }
5745
+ });
5746
+ });
5747
+ function literal(value, params) {
5748
+ return new ZodLiteral({
5749
+ type: "literal",
5750
+ values: Array.isArray(value) ? value : [value],
5751
+ ...util_exports.normalizeParams(params)
5752
+ });
5753
+ }
5671
5754
  var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
5672
5755
  _ensureDefaultMemoizer();
5673
5756
  $ZodTransform.init(inst, def);
@@ -5982,6 +6065,7 @@ function defineTool(def) {
5982
6065
  }
5983
6066
  var SAVINGS_TYPES = ["compute", "storage", "network", "database", "serverless", "governance"];
5984
6067
  var SECURITY_SOURCES = ["own", "corroborated", "securityhub", "guardduty", "defender", "scc"];
6068
+ var SECURITY_CATEGORIES = ["security_network", "security_exposure", "security_encryption", "security_iam", "security_logging", "security_secrets"];
5985
6069
  var AGENT_STATUSES = ["proposed", "pending_approval", "pending_second_approval", "approved", "executing", "completed", "failed", "cancelled", "expired"];
5986
6070
  var BillingPeriod = string2().regex(/^\d{4}-(0[1-9]|1[0-2])$/, "Use YYYY-MM");
5987
6071
  var ACCOUNT_ID = { type: "string", description: "Account identifier, as returned by list_accounts." };
@@ -6138,7 +6222,7 @@ var TOOLS = [
6138
6222
  }),
6139
6223
  defineTool({
6140
6224
  name: "list_security_findings",
6141
- description: "List the security findings of the latest security scan of one account (up to 500, most severe first), with attack chains and a diff against the previous scan. Requires the security:read scope, the Pro plan and the security add-on on that account.",
6225
+ description: 'List the security findings of the latest security scan of one account (up to 500, most severe first), with attack chains and a diff against the previous scan. Use category "security_iam" for the permissions view: effective administrators, unused identities, keys and service accounts, granted permissions that are not used, and assignments to deleted identities. Requires the security:read scope, the Pro plan and the security add-on on that account.',
6142
6226
  inputSchema: {
6143
6227
  type: "object",
6144
6228
  properties: {
@@ -6147,16 +6231,25 @@ var TOOLS = [
6147
6231
  type: "string",
6148
6232
  enum: [...SECURITY_SOURCES],
6149
6233
  description: "Filter by origin: own rules, corroborated, or a native tool (optional)."
6234
+ },
6235
+ category: {
6236
+ type: "string",
6237
+ enum: [...SECURITY_CATEGORIES],
6238
+ description: 'Filter by rule category (optional); "security_iam" is the permissions view.'
6150
6239
  }
6151
6240
  },
6152
6241
  required: ["accountId"]
6153
6242
  },
6154
- argsSchema: object({ accountId: string2().min(1), source: _enum(SECURITY_SOURCES).optional() }),
6155
- handler: async ({ accountId, source }, config2) => apiGet("/v1/security/findings", { accountId, source }, config2)
6243
+ argsSchema: object({
6244
+ accountId: string2().min(1),
6245
+ source: _enum(SECURITY_SOURCES).optional(),
6246
+ category: _enum(SECURITY_CATEGORIES).optional()
6247
+ }),
6248
+ handler: async ({ accountId, source, category }, config2) => apiGet("/v1/security/findings", { accountId, source, category }, config2)
6156
6249
  }),
6157
6250
  defineTool({
6158
6251
  name: "get_security_critical_changes",
6159
- description: "List the critical configuration changes of the last 7 days in one AWS account, read from CloudTrail (up to 100, newest first): public bucket or snapshot, remote admin open to the internet, logging turned off, root use, admin granted. Each comes with who made it and, for rule-backed changes, whether a re-check confirmed the risk. Accounts outside AWS, or without the security add-on, return supported false and an empty list. Requires the security:read scope and the Pro plan or above.",
6252
+ description: "List the critical configuration changes of the last 7 days in one account (up to 100, newest first), read from CloudTrail in AWS, the activity log in Azure or the Admin Activity audit logs in GCP: public bucket, storage or snapshot, remote admin open to the internet, logging turned off, root use, admin granted. Each comes with who made it and, for rule-backed changes, whether a re-check confirmed the risk. Accounts without the security add-on return supported false and an empty list. Requires the security:read scope and the Pro plan or above.",
6160
6253
  inputSchema: {
6161
6254
  type: "object",
6162
6255
  properties: { accountId: { type: "string", description: "Account identifier, as returned by list_accounts." } },
@@ -6165,6 +6258,17 @@ var TOOLS = [
6165
6258
  argsSchema: object({ accountId: string2().min(1) }),
6166
6259
  handler: async ({ accountId }, config2) => apiGet("/v1/security/critical-changes", { accountId }, config2)
6167
6260
  }),
6261
+ defineTool({
6262
+ name: "list_security_vulnerabilities",
6263
+ description: "List the vulnerabilities (CVEs) that the cloud native scanner already found in one account (Amazon Inspector or ECR basic scanning, Microsoft Defender for Cloud, GCP Artifact Analysis and VM Manager), up to 200, highest priority first. Each one has the cloud severity and an effective severity that rises when the resource is exposed to the internet, has a known exploit or is unused according to a cost rule (low CPU is shown as context only). AAA Sentinel does not scan on its own: tools shows whether each scanner is active, absent or could not be read, truncated whether the cloud has more than the cap, and partial why the list may be incomplete (scanner missing in some regions or resource types listed in uncovered, failed reads, time budget, unreadable entries, expired rows). Amazon Inspector only sees image use on ECS and EKS: when the account has container Lambdas, App Runner services or images not in use there, uncovered.gaps says ecr_images_outside_ecs_eks and those images come last with imageInUse false. An account without the security add-on returns access teaser and an empty list, which does not mean it has no vulnerabilities. bySeverity counts the effective severity. Requires the security:read scope and the Pro plan or above.",
6264
+ inputSchema: {
6265
+ type: "object",
6266
+ properties: { accountId: { type: "string", description: "Account identifier, as returned by list_accounts." } },
6267
+ required: ["accountId"]
6268
+ },
6269
+ argsSchema: object({ accountId: string2().min(1) }),
6270
+ handler: async ({ accountId }, config2) => apiGet("/v1/security/vulnerabilities", { accountId }, config2)
6271
+ }),
6168
6272
  defineTool({
6169
6273
  name: "get_security_conformance",
6170
6274
  description: "Get CIS benchmark coverage for one account, or for every account of a managed client (clientId, Business plan). Pass exactly one of accountId or clientId. Requires the security:read scope, plus reports:read when using clientId.",
@@ -6180,6 +6284,26 @@ var TOOLS = [
6180
6284
  }),
6181
6285
  handler: async ({ accountId, clientId: clientId2 }, config2) => apiGet("/v1/security/conformance", { accountId, clientId: clientId2 }, config2)
6182
6286
  }),
6287
+ defineTool({
6288
+ name: "get_security_posture_history",
6289
+ description: "Get how the security posture changed over 30, 90 or 365 days (default 90) for one account, or for every account with the security add-on of a managed client (clientId, Business plan, up to 20 accounts; omitted counts the rest). Returns points, one per UTC day (the last scan of that day: score, scored/total rules, open findings by severity, events), and summary: from/to (Score of the first and last point), resolved (distinct findings gone in a scan that fully evaluated their rule), opened (new, from rules already fully evaluated before), surfaced (new but not comparable: rule not fully evaluated before, or an external tool), unverified (gone without confirmation), meanFixDays by severity, comparable and notComparableReasons. When comparable is false, do not describe the Score change as the account getting better or worse. Points keep the Score computed each day, without discounting risks accepted later (acceptedRisks). Pass exactly one of accountId or clientId. Requires the security:read scope, plus reports:read when using clientId.",
6290
+ inputSchema: {
6291
+ type: "object",
6292
+ properties: {
6293
+ accountId: { type: "string", description: "Account identifier (use this or clientId)." },
6294
+ clientId: { type: "string", description: "Managed client identifier (use this or accountId)." },
6295
+ days: { type: "number", enum: [30, 90, 365], description: "Period in days (optional, default 90)." }
6296
+ }
6297
+ },
6298
+ argsSchema: object({
6299
+ accountId: string2().min(1).optional(),
6300
+ clientId: string2().min(1).optional(),
6301
+ days: union([literal(30), literal(90), literal(365)]).optional()
6302
+ }).refine((a) => Boolean(a.accountId) !== Boolean(a.clientId), {
6303
+ message: "Pass exactly one of accountId or clientId"
6304
+ }),
6305
+ handler: async ({ accountId, clientId: clientId2, days }, config2) => apiGet("/v1/security/posture-history", { accountId, clientId: clientId2, days: days === void 0 ? void 0 : String(days) }, config2)
6306
+ }),
6183
6307
  // ── Cuentas y costes ───────────────────────────────────────
6184
6308
  defineTool({
6185
6309
  name: "get_account",
@@ -6516,7 +6640,7 @@ function findTool(name) {
6516
6640
 
6517
6641
  // src/protocol.ts
6518
6642
  var SERVER_NAME = "aaa-sentinel-mcp";
6519
- var SERVER_VERSION = "0.6.0";
6643
+ var SERVER_VERSION = "0.8.0";
6520
6644
  var SUPPORTED_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
6521
6645
  var PARSE_ERROR = -32700;
6522
6646
  var INVALID_REQUEST = -32600;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aaa-sentinel/mcp-server",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Read-only MCP server for AAA Sentinel: query cloud costs, savings, security posture, AI spend, uptime monitoring, the remediation agent and managed clients from an AI assistant",
5
5
  "license": "MIT",
6
6
  "type": "module",