@aaa-sentinel/mcp-server 0.2.0 → 0.3.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.
- package/README.md +70 -16
- package/dist/cli.js +288 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# @aaa-sentinel/mcp-server
|
|
2
2
|
|
|
3
|
-
Lets an AI assistant read your
|
|
4
|
-
|
|
5
|
-
ask *"which of my AWS
|
|
6
|
-
|
|
3
|
+
Lets an AI assistant read your AAA Sentinel data — cloud costs, savings and forecasts, security
|
|
4
|
+
posture, AI spend, uptime monitoring, the autonomous agent and your managed clients — through the
|
|
5
|
+
[Model Context Protocol](https://modelcontextprotocol.io), so you can ask *"which of my AWS
|
|
6
|
+
accounts is bleeding the most money this month, and why"*, *"what is down right now"* or *"how
|
|
7
|
+
much have we spent on AI this month"* in the chat window you already have open instead of a
|
|
8
|
+
dashboard you have to remember to visit.
|
|
7
9
|
|
|
8
10
|
> **User** — Which account has the most waste right now?
|
|
9
11
|
>
|
|
@@ -12,15 +14,22 @@ window you already have open instead of a dashboard you have to remember to visi
|
|
|
12
14
|
> 11 unattached EBS volumes ($412/mo), 3 idle RDS instances ($980/mo) and an over-provisioned
|
|
13
15
|
> NAT gateway ($338/mo).
|
|
14
16
|
|
|
17
|
+
> **User** — Why was checkout failing this morning?
|
|
18
|
+
>
|
|
19
|
+
> **Assistant** *(calls `list_monitoring_services`, then `get_service_history`, then `list_monitor_results`)* —
|
|
20
|
+
> *Checkout* went down at 07:42 UTC and recovered at 08:05. The culprit was *Payments API*: 23
|
|
21
|
+
> consecutive checks timed out after 5 s, confirmed from a second region. The other two components
|
|
22
|
+
> stayed healthy.
|
|
23
|
+
|
|
15
24
|
## Requirements
|
|
16
25
|
|
|
17
26
|
- Node.js 20 or newer.
|
|
18
27
|
- An OAuth2 application created in the [developer portal](https://app.aaa-sentinel.com/developer/apps).
|
|
19
28
|
- Scopes depend on what you want the assistant to be able to read — see the table below. Grant
|
|
20
29
|
only those; the scopes you leave out are simply not reachable from the assistant.
|
|
21
|
-
- A **Pro** plan
|
|
22
|
-
and the
|
|
23
|
-
|
|
30
|
+
- A **Pro** plan or above: the API is not available on the free plan. Chargeback, cost anomalies,
|
|
31
|
+
unit cost, managed clients and the agent need **Business**, and the security tools also need the
|
|
32
|
+
security add-on on the account — the table below says which.
|
|
24
33
|
|
|
25
34
|
## Configuration
|
|
26
35
|
|
|
@@ -80,14 +89,18 @@ connected to a server that can answer nothing is worse than a client that report
|
|
|
80
89
|
|
|
81
90
|
## Tools
|
|
82
91
|
|
|
83
|
-
All
|
|
92
|
+
All of them are **read-only**, and together they cover every read endpoint of the public API
|
|
93
|
+
except four that make no sense in a conversation: the data to connect a new account, the
|
|
94
|
+
telemetry probe used by SDKs, the Jira/Linear configuration (it carries partially masked tokens)
|
|
95
|
+
and the `health+json` endpoint for load balancers — `get_monitoring_service` returns the same
|
|
96
|
+
status as plain JSON.
|
|
84
97
|
|
|
85
98
|
| Tool | Arguments | Scope | Plan |
|
|
86
99
|
| --- | --- | --- | --- |
|
|
87
|
-
| `list_accounts` | — | `accounts:read` |
|
|
88
|
-
| `list_scans` | `accountId` | `scans:read` |
|
|
89
|
-
| `get_scan` | `scanId` | `scans:read` |
|
|
90
|
-
| `list_findings` | `scanId`, `includeSuppressed?` | `findings:read` |
|
|
100
|
+
| `list_accounts` | — | `accounts:read` | Pro |
|
|
101
|
+
| `list_scans` | `accountId` | `scans:read` | Pro |
|
|
102
|
+
| `get_scan` | `scanId` | `scans:read` | Pro |
|
|
103
|
+
| `list_findings` | `scanId`, `includeSuppressed?` | `findings:read` | Pro |
|
|
91
104
|
| `get_reports_summary` | `accountId?` | `reports:read` | Pro |
|
|
92
105
|
| `list_savings` | `accountId?`, `type?` | `savings:read` | Pro |
|
|
93
106
|
| `get_chargeback` | `clientId?` | `reports:read` | Business |
|
|
@@ -97,10 +110,51 @@ All fourteen are **read-only**.
|
|
|
97
110
|
| `get_security_overview` | — | `security:read` | Pro + security add-on |
|
|
98
111
|
| `get_security_score` | `accountId` | `security:read` | Pro + security add-on |
|
|
99
112
|
| `list_security_findings` | `accountId`, `source?` | `security:read` | Pro + security add-on |
|
|
100
|
-
| `get_security_conformance` | `accountId` or `clientId` | `security:read`
|
|
101
|
-
|
|
102
|
-
`
|
|
103
|
-
`
|
|
113
|
+
| `get_security_conformance` | `accountId` or `clientId` | `security:read` | Pro + security add-on |
|
|
114
|
+
| `get_account` | `accountId` | `accounts:read` | Pro |
|
|
115
|
+
| `get_account_monthly_costs` | `accountId` | `accounts:read` | Pro |
|
|
116
|
+
| `get_cost_history` | `accountId` | `reports:read` | Pro |
|
|
117
|
+
| `get_cost_by_tags` | `accountId` | `reports:read` | Pro |
|
|
118
|
+
| `get_multicloud_report` | — | `reports:read` | Pro |
|
|
119
|
+
| `list_alerts` | `limit?` | `alerts:read` | Pro |
|
|
120
|
+
| `list_disabled_rules` | — | `rules:read` | Pro |
|
|
121
|
+
| `list_business_metrics` | — | `metrics:read` | Business |
|
|
122
|
+
| `get_metric_values` | `metricId`, `billingPeriod` | `metrics:read` | Business |
|
|
123
|
+
| `get_unit_cost` | `metricId`, `billingPeriod` | `metrics:read` | Business |
|
|
124
|
+
| `list_ai_connections` | — | `ai:read` | Pro |
|
|
125
|
+
| `get_ai_usage` | `days?`, `groupBy?` | `ai:read` | Pro |
|
|
126
|
+
| `get_ai_connection_usage` | `connectionId` | `ai:read` | Pro |
|
|
127
|
+
| `list_clients` | — | `clients:read` | Business |
|
|
128
|
+
| `get_client` | `clientId` | `clients:read` | Business |
|
|
129
|
+
| `get_client_billing` | `clientId` | `clients:read` | Business |
|
|
130
|
+
| `get_agent_dashboard` | `clientId?` | `agent:read` | Business |
|
|
131
|
+
| `list_agent_actions` | `status?`, `accountId?`, `type?`, `limit?`, `cursor?` | `agent:read` | Business |
|
|
132
|
+
| `get_agent_action` | `actionId` | `agent:read` | Business |
|
|
133
|
+
| `list_agent_history` | `status?`, `limit?`, `cursor?` | `agent:read` | Business |
|
|
134
|
+
| `list_agent_schedules` | — | `agent:read` | Business |
|
|
135
|
+
| `get_agent_schedule` | `scheduleId` | `agent:read` | Business |
|
|
136
|
+
| `list_agent_playbooks` | — | `agent:read` | Business |
|
|
137
|
+
| `get_agent_playbook` | `playbookId` | `agent:read` | Business |
|
|
138
|
+
| `list_agent_playbook_templates` | — | `agent:read` | Business |
|
|
139
|
+
| `list_monitors` | `pinned?`, `clientId?` | `monitoring:read` | Pro |
|
|
140
|
+
| `get_monitor` | `monitorId` | `monitoring:read` | Pro |
|
|
141
|
+
| `list_monitor_results` | `monitorId`, `limit?`, `before?` | `monitoring:read` | Pro |
|
|
142
|
+
| `get_monitor_uptime` | `monitorId`, `days?` | `monitoring:read` | Pro |
|
|
143
|
+
| `list_monitoring_services` | — | `monitoring:read` | Pro |
|
|
144
|
+
| `get_monitoring_service` | `serviceId` | `monitoring:read` | Pro |
|
|
145
|
+
| `get_service_history` | `serviceId`, `limit?` | `monitoring:read` | Pro |
|
|
146
|
+
|
|
147
|
+
In `list_savings`, `type` is one of `compute`, `storage`, `network`, `database`, `serverless`,
|
|
148
|
+
`governance`. `source` is one of `own`, `corroborated`, `securityhub`, `guardduty`, `defender`,
|
|
149
|
+
`scc`. `billingPeriod` is a month as `YYYY-MM`. The agent `status` filter is one of `proposed`,
|
|
150
|
+
`pending_approval`, `pending_second_approval`, `approved`, `executing`, `completed`, `failed`,
|
|
151
|
+
`cancelled`, `expired`; `pending_approval` also returns the second-approval queue, since both
|
|
152
|
+
wait for a human.
|
|
153
|
+
|
|
154
|
+
A monitor is `up`, `suspect` or `confirming` (a failure being confirmed from a second region —
|
|
155
|
+
not an outage yet), `down`, or `recovering` (still counted as down until the recovery is
|
|
156
|
+
confirmed). The last result carries a reason code such as `timeout`, `status_mismatch` or
|
|
157
|
+
`queue_dlq_not_empty`; the full list is in the API reference.
|
|
104
158
|
|
|
105
159
|
The security tools need the security add-on enabled on the account (20 €/month per account).
|
|
106
160
|
Without it they answer with `access: "teaser"` and no scan data, so the assistant can tell
|
package/dist/cli.js
CHANGED
|
@@ -4190,6 +4190,24 @@ function defineTool(def) {
|
|
|
4190
4190
|
}
|
|
4191
4191
|
var SAVINGS_TYPES = ["compute", "storage", "network", "database", "serverless", "governance"];
|
|
4192
4192
|
var SECURITY_SOURCES = ["own", "corroborated", "securityhub", "guardduty", "defender", "scc"];
|
|
4193
|
+
var AGENT_STATUSES = ["proposed", "pending_approval", "pending_second_approval", "approved", "executing", "completed", "failed", "cancelled", "expired"];
|
|
4194
|
+
var BillingPeriod = external_exports.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/, "Use YYYY-MM");
|
|
4195
|
+
var ACCOUNT_ID = { type: "string", description: "Account identifier, as returned by list_accounts." };
|
|
4196
|
+
var CLIENT_ID = { type: "string", description: "Managed client identifier, as returned by list_clients." };
|
|
4197
|
+
var MONITOR_ID = { type: "string", description: "Monitor identifier, as returned by list_monitors." };
|
|
4198
|
+
var SERVICE_ID = { type: "string", description: "Service identifier, as returned by list_monitoring_services." };
|
|
4199
|
+
var METRIC_ID = { type: "string", description: "Business metric identifier, as returned by list_business_metrics." };
|
|
4200
|
+
var BILLING_PERIOD = { type: "string", pattern: "^\\d{4}-(0[1-9]|1[0-2])$", description: "Month, as YYYY-MM." };
|
|
4201
|
+
var CURSOR = { type: "string", description: "The cursor returned by the previous page (optional)." };
|
|
4202
|
+
var AGENT_STATUS = {
|
|
4203
|
+
type: "string",
|
|
4204
|
+
enum: [...AGENT_STATUSES],
|
|
4205
|
+
description: 'Filter by status (optional). "pending_approval" also includes "pending_second_approval": both wait for a human.'
|
|
4206
|
+
};
|
|
4207
|
+
function objectWith(properties, required) {
|
|
4208
|
+
return { type: "object", properties, ...required ? { required } : {} };
|
|
4209
|
+
}
|
|
4210
|
+
var asText = (value) => value === void 0 ? void 0 : String(value);
|
|
4193
4211
|
var TOOLS = [
|
|
4194
4212
|
defineTool({
|
|
4195
4213
|
name: "list_accounts",
|
|
@@ -4358,6 +4376,275 @@ var TOOLS = [
|
|
|
4358
4376
|
message: "Pass exactly one of accountId or clientId"
|
|
4359
4377
|
}),
|
|
4360
4378
|
handler: async ({ accountId, clientId: clientId2 }, config) => apiGet("/v1/security/conformance", { accountId, clientId: clientId2 }, config)
|
|
4379
|
+
}),
|
|
4380
|
+
// ── Cuentas y costes ───────────────────────────────────────
|
|
4381
|
+
defineTool({
|
|
4382
|
+
name: "get_account",
|
|
4383
|
+
description: "Get one connected cloud account: provider, connection status, enabled modules (cost, security, monitoring) and managed client. Requires the accounts:read scope.",
|
|
4384
|
+
inputSchema: objectWith({ accountId: ACCOUNT_ID }, ["accountId"]),
|
|
4385
|
+
argsSchema: external_exports.object({ accountId: external_exports.string().min(1) }),
|
|
4386
|
+
handler: async ({ accountId }, config) => apiGet(`/v1/accounts/${encodeURIComponent(accountId)}`, void 0, config)
|
|
4387
|
+
}),
|
|
4388
|
+
defineTool({
|
|
4389
|
+
name: "get_account_monthly_costs",
|
|
4390
|
+
description: "Get the monthly cost of one cloud account for the last 6 months (from the latest completed scan of each month). Requires the accounts:read scope.",
|
|
4391
|
+
inputSchema: objectWith({ accountId: ACCOUNT_ID }, ["accountId"]),
|
|
4392
|
+
argsSchema: external_exports.object({ accountId: external_exports.string().min(1) }),
|
|
4393
|
+
handler: async ({ accountId }, config) => apiGet(`/v1/accounts/${encodeURIComponent(accountId)}/monthly-costs`, void 0, config)
|
|
4394
|
+
}),
|
|
4395
|
+
defineTool({
|
|
4396
|
+
name: "get_cost_history",
|
|
4397
|
+
description: "Get the spend history of one cloud account for the last 12 months. Requires the reports:read scope and the Pro plan or above.",
|
|
4398
|
+
inputSchema: objectWith({ accountId: ACCOUNT_ID }, ["accountId"]),
|
|
4399
|
+
argsSchema: external_exports.object({ accountId: external_exports.string().min(1) }),
|
|
4400
|
+
handler: async ({ accountId }, config) => apiGet(`/v1/reports/history/${encodeURIComponent(accountId)}`, void 0, config)
|
|
4401
|
+
}),
|
|
4402
|
+
defineTool({
|
|
4403
|
+
name: "get_cost_by_tags",
|
|
4404
|
+
description: "Break down the cost of one cloud account by project/team tag and region. Requires the reports:read scope and the Pro plan or above.",
|
|
4405
|
+
inputSchema: objectWith({ accountId: ACCOUNT_ID }, ["accountId"]),
|
|
4406
|
+
argsSchema: external_exports.object({ accountId: external_exports.string().min(1) }),
|
|
4407
|
+
handler: async ({ accountId }, config) => apiGet(`/v1/reports/by-tags/${encodeURIComponent(accountId)}`, void 0, config)
|
|
4408
|
+
}),
|
|
4409
|
+
defineTool({
|
|
4410
|
+
name: "get_multicloud_report",
|
|
4411
|
+
description: "Compare spend across AWS, Azure and GCP in one unified view, with migration recommendations. Requires the reports:read scope and the Pro plan or above.",
|
|
4412
|
+
inputSchema: { type: "object", properties: {} },
|
|
4413
|
+
argsSchema: external_exports.object({}),
|
|
4414
|
+
handler: async (_args, config) => apiGet("/v1/reports/multicloud", void 0, config)
|
|
4415
|
+
}),
|
|
4416
|
+
defineTool({
|
|
4417
|
+
name: "list_alerts",
|
|
4418
|
+
description: "List the most recent alerts raised by the platform (cost, security, monitoring), newest first. Requires the alerts:read scope.",
|
|
4419
|
+
inputSchema: objectWith({ limit: { type: "integer", minimum: 1, maximum: 100, description: "How many alerts to return (1-100, default 50)." } }),
|
|
4420
|
+
argsSchema: external_exports.object({ limit: external_exports.number().int().min(1).max(100).optional() }),
|
|
4421
|
+
handler: async ({ limit }, config) => apiGet("/v1/alerts", { limit: asText(limit) }, config)
|
|
4422
|
+
}),
|
|
4423
|
+
defineTool({
|
|
4424
|
+
name: "list_disabled_rules",
|
|
4425
|
+
description: 'List the detection rules the customer has turned off, so you can tell "nothing found" apart from "that check is disabled". Requires the rules:read scope.',
|
|
4426
|
+
inputSchema: { type: "object", properties: {} },
|
|
4427
|
+
argsSchema: external_exports.object({}),
|
|
4428
|
+
handler: async (_args, config) => apiGet("/v1/rules/settings", void 0, config)
|
|
4429
|
+
}),
|
|
4430
|
+
// ── Unit economics ─────────────────────────────────────────
|
|
4431
|
+
defineTool({
|
|
4432
|
+
name: "list_business_metrics",
|
|
4433
|
+
description: "List the business metrics the organisation declares (orders, active users...), used to compute unit cost. Requires the metrics:read scope and the Business plan.",
|
|
4434
|
+
inputSchema: { type: "object", properties: {} },
|
|
4435
|
+
argsSchema: external_exports.object({}),
|
|
4436
|
+
handler: async (_args, config) => apiGet("/v1/metrics", void 0, config)
|
|
4437
|
+
}),
|
|
4438
|
+
defineTool({
|
|
4439
|
+
name: "get_metric_values",
|
|
4440
|
+
description: "Get the declared values of one business metric within a month. Requires the metrics:read scope and the Business plan.",
|
|
4441
|
+
inputSchema: objectWith({ metricId: METRIC_ID, billingPeriod: BILLING_PERIOD }, ["metricId", "billingPeriod"]),
|
|
4442
|
+
argsSchema: external_exports.object({ metricId: external_exports.string().min(1), billingPeriod: BillingPeriod }),
|
|
4443
|
+
handler: async ({ metricId, billingPeriod }, config) => apiGet(`/v1/metrics/${encodeURIComponent(metricId)}/values`, { billingPeriod }, config)
|
|
4444
|
+
}),
|
|
4445
|
+
defineTool({
|
|
4446
|
+
name: "get_unit_cost",
|
|
4447
|
+
description: "Get the unit cost of one business metric in a month (cloud cost divided by the metric, e.g. cost per order). Requires the metrics:read scope and the Business plan.",
|
|
4448
|
+
inputSchema: objectWith({ metricId: METRIC_ID, billingPeriod: BILLING_PERIOD }, ["metricId", "billingPeriod"]),
|
|
4449
|
+
argsSchema: external_exports.object({ metricId: external_exports.string().min(1), billingPeriod: BillingPeriod }),
|
|
4450
|
+
handler: async ({ metricId, billingPeriod }, config) => apiGet(`/v1/metrics/${encodeURIComponent(metricId)}/unit-cost`, { billingPeriod }, config)
|
|
4451
|
+
}),
|
|
4452
|
+
// ── Gasto en IA ────────────────────────────────────────────
|
|
4453
|
+
defineTool({
|
|
4454
|
+
name: "list_ai_connections",
|
|
4455
|
+
description: "List the connections to AI providers (OpenAI, Anthropic, Bedrock, Vertex...) with their status and managed client. Start here to obtain a connectionId. Requires the ai:read scope and the Pro plan or above.",
|
|
4456
|
+
inputSchema: { type: "object", properties: {} },
|
|
4457
|
+
argsSchema: external_exports.object({}),
|
|
4458
|
+
handler: async (_args, config) => apiGet("/v1/ai-providers", void 0, config)
|
|
4459
|
+
}),
|
|
4460
|
+
defineTool({
|
|
4461
|
+
name: "get_ai_usage",
|
|
4462
|
+
description: "Get aggregated AI spend and usage across every AI connection, with billed and estimated amounts kept apart. Requires the ai:read scope and the Pro plan or above.",
|
|
4463
|
+
inputSchema: objectWith({
|
|
4464
|
+
days: { type: "integer", minimum: 1, description: "Days back (default 30); capped to the history your plan keeps." },
|
|
4465
|
+
groupBy: { type: "string", enum: ["holder"], description: 'Use "holder" to group individual connections by the person who holds them.' }
|
|
4466
|
+
}),
|
|
4467
|
+
argsSchema: external_exports.object({ days: external_exports.number().int().min(1).optional(), groupBy: external_exports.enum(["holder"]).optional() }),
|
|
4468
|
+
handler: async ({ days, groupBy }, config) => apiGet("/v1/ai-providers/usage", { days: asText(days), groupBy }, config)
|
|
4469
|
+
}),
|
|
4470
|
+
defineTool({
|
|
4471
|
+
name: "get_ai_connection_usage",
|
|
4472
|
+
description: "Get the AI spend and usage of one connection, by day and by allocation dimension (model, project, key...). Requires the ai:read scope and the Pro plan or above.",
|
|
4473
|
+
inputSchema: objectWith({ connectionId: { type: "string", description: "Connection identifier, as returned by list_ai_connections." } }, ["connectionId"]),
|
|
4474
|
+
argsSchema: external_exports.object({ connectionId: external_exports.string().min(1) }),
|
|
4475
|
+
handler: async ({ connectionId }, config) => apiGet(`/v1/ai-providers/${encodeURIComponent(connectionId)}/usage`, void 0, config)
|
|
4476
|
+
}),
|
|
4477
|
+
// ── Clientes gestionados (MSP) ─────────────────────────────
|
|
4478
|
+
defineTool({
|
|
4479
|
+
name: "list_clients",
|
|
4480
|
+
description: "List the managed clients of an MSP or consultancy. Start here to obtain a clientId. Requires the clients:read scope and the Business plan.",
|
|
4481
|
+
inputSchema: { type: "object", properties: {} },
|
|
4482
|
+
argsSchema: external_exports.object({}),
|
|
4483
|
+
handler: async (_args, config) => apiGet("/v1/clients", void 0, config)
|
|
4484
|
+
}),
|
|
4485
|
+
defineTool({
|
|
4486
|
+
name: "get_client",
|
|
4487
|
+
description: "Get one managed client with the cloud accounts and AI connections assigned to it. Requires the clients:read scope and the Business plan.",
|
|
4488
|
+
inputSchema: objectWith({ clientId: CLIENT_ID }, ["clientId"]),
|
|
4489
|
+
argsSchema: external_exports.object({ clientId: external_exports.string().min(1) }),
|
|
4490
|
+
handler: async ({ clientId: clientId2 }, config) => apiGet(`/v1/clients/${encodeURIComponent(clientId2)}`, void 0, config)
|
|
4491
|
+
}),
|
|
4492
|
+
defineTool({
|
|
4493
|
+
name: "get_client_billing",
|
|
4494
|
+
description: "Get the billing base of one managed client: its cost by account plus the configured margin, ready to invoice. Requires the clients:read scope and the Business plan.",
|
|
4495
|
+
inputSchema: objectWith({ clientId: CLIENT_ID }, ["clientId"]),
|
|
4496
|
+
argsSchema: external_exports.object({ clientId: external_exports.string().min(1) }),
|
|
4497
|
+
handler: async ({ clientId: clientId2 }, config) => apiGet(`/v1/clients/${encodeURIComponent(clientId2)}/billing`, void 0, config)
|
|
4498
|
+
}),
|
|
4499
|
+
// ── Agente autónomo (solo lectura: aprobar o lanzar se queda en la app) ──
|
|
4500
|
+
defineTool({
|
|
4501
|
+
name: "get_agent_dashboard",
|
|
4502
|
+
description: "Get the autonomous agent KPIs: actions executed and pending approval, savings achieved, active schedules and playbooks \u2014 for the whole organisation, or for one managed client. Requires the agent:read scope (plus clients:read with clientId) and the Business plan.",
|
|
4503
|
+
inputSchema: objectWith({ clientId: { ...CLIENT_ID, description: "Restrict the KPIs to the accounts of one managed client (optional)." } }),
|
|
4504
|
+
argsSchema: external_exports.object({ clientId: external_exports.string().min(1).optional() }),
|
|
4505
|
+
handler: async ({ clientId: clientId2 }, config) => apiGet(clientId2 ? `/v1/clients/${encodeURIComponent(clientId2)}/agent/dashboard` : "/v1/agent/dashboard", void 0, config)
|
|
4506
|
+
}),
|
|
4507
|
+
defineTool({
|
|
4508
|
+
name: "list_agent_actions",
|
|
4509
|
+
description: 'List the remediation actions proposed or executed by the autonomous agent, newest first, with optional filters. Use status "pending_approval" to see what is waiting for a human. Paginated: pass the returned cursor to get the next page. Requires the agent:read scope and the Business plan.',
|
|
4510
|
+
inputSchema: objectWith({
|
|
4511
|
+
status: AGENT_STATUS,
|
|
4512
|
+
accountId: { ...ACCOUNT_ID, description: "Restrict to one account (optional)." },
|
|
4513
|
+
type: { type: "string", description: 'Restrict to one action type, e.g. "stop_instance" (optional).' },
|
|
4514
|
+
limit: { type: "integer", minimum: 1, maximum: 100, description: "Page size (default 20)." },
|
|
4515
|
+
cursor: CURSOR
|
|
4516
|
+
}),
|
|
4517
|
+
argsSchema: external_exports.object({
|
|
4518
|
+
status: external_exports.enum(AGENT_STATUSES).optional(),
|
|
4519
|
+
accountId: external_exports.string().min(1).optional(),
|
|
4520
|
+
type: external_exports.string().min(1).optional(),
|
|
4521
|
+
limit: external_exports.number().int().min(1).max(100).optional(),
|
|
4522
|
+
cursor: external_exports.string().min(1).optional()
|
|
4523
|
+
}),
|
|
4524
|
+
handler: async ({ status, accountId, type, limit, cursor }, config) => apiGet("/v1/agent/actions", { status, accountId, type, limit: asText(limit), cursor }, config)
|
|
4525
|
+
}),
|
|
4526
|
+
defineTool({
|
|
4527
|
+
name: "get_agent_action",
|
|
4528
|
+
description: "Get the full detail of one agent action: what it does, why, its estimated saving, approvals and execution result. Requires the agent:read scope and the Business plan.",
|
|
4529
|
+
inputSchema: objectWith({ actionId: { type: "string", description: "Action identifier, as returned by list_agent_actions." } }, ["actionId"]),
|
|
4530
|
+
argsSchema: external_exports.object({ actionId: external_exports.string().min(1) }),
|
|
4531
|
+
handler: async ({ actionId }, config) => apiGet(`/v1/agent/actions/${encodeURIComponent(actionId)}`, void 0, config)
|
|
4532
|
+
}),
|
|
4533
|
+
defineTool({
|
|
4534
|
+
name: "list_agent_history",
|
|
4535
|
+
description: "List the paginated history of agent actions, optionally by status. Pass the returned cursor to get the next page. Requires the agent:read scope and the Business plan.",
|
|
4536
|
+
inputSchema: objectWith({
|
|
4537
|
+
status: AGENT_STATUS,
|
|
4538
|
+
limit: { type: "integer", minimum: 1, maximum: 100, description: "Page size (default 50)." },
|
|
4539
|
+
cursor: CURSOR
|
|
4540
|
+
}),
|
|
4541
|
+
argsSchema: external_exports.object({
|
|
4542
|
+
status: external_exports.enum(AGENT_STATUSES).optional(),
|
|
4543
|
+
limit: external_exports.number().int().min(1).max(100).optional(),
|
|
4544
|
+
cursor: external_exports.string().min(1).optional()
|
|
4545
|
+
}),
|
|
4546
|
+
handler: async ({ status, limit, cursor }, config) => apiGet("/v1/agent/history", { status, limit: asText(limit), cursor }, config)
|
|
4547
|
+
}),
|
|
4548
|
+
defineTool({
|
|
4549
|
+
name: "list_agent_schedules",
|
|
4550
|
+
description: "List the start/stop schedules the agent applies to resources (e.g. stop dev instances at night). Requires the agent:read scope and the Business plan.",
|
|
4551
|
+
inputSchema: { type: "object", properties: {} },
|
|
4552
|
+
argsSchema: external_exports.object({}),
|
|
4553
|
+
handler: async (_args, config) => apiGet("/v1/agent/schedules", void 0, config)
|
|
4554
|
+
}),
|
|
4555
|
+
defineTool({
|
|
4556
|
+
name: "get_agent_schedule",
|
|
4557
|
+
description: "Get one agent schedule by its id. Requires the agent:read scope and the Business plan.",
|
|
4558
|
+
inputSchema: objectWith({ scheduleId: { type: "string", description: "Schedule identifier, as returned by list_agent_schedules." } }, ["scheduleId"]),
|
|
4559
|
+
argsSchema: external_exports.object({ scheduleId: external_exports.string().min(1) }),
|
|
4560
|
+
handler: async ({ scheduleId }, config) => apiGet(`/v1/agent/schedules/${encodeURIComponent(scheduleId)}`, void 0, config)
|
|
4561
|
+
}),
|
|
4562
|
+
defineTool({
|
|
4563
|
+
name: "list_agent_playbooks",
|
|
4564
|
+
description: "List the remediation playbooks configured for the agent. Requires the agent:read scope and the Business plan.",
|
|
4565
|
+
inputSchema: { type: "object", properties: {} },
|
|
4566
|
+
argsSchema: external_exports.object({}),
|
|
4567
|
+
handler: async (_args, config) => apiGet("/v1/agent/playbooks", void 0, config)
|
|
4568
|
+
}),
|
|
4569
|
+
defineTool({
|
|
4570
|
+
name: "get_agent_playbook",
|
|
4571
|
+
description: "Get one remediation playbook by its id. Requires the agent:read scope and the Business plan.",
|
|
4572
|
+
inputSchema: objectWith({ playbookId: { type: "string", description: "Playbook identifier, as returned by list_agent_playbooks." } }, ["playbookId"]),
|
|
4573
|
+
argsSchema: external_exports.object({ playbookId: external_exports.string().min(1) }),
|
|
4574
|
+
handler: async ({ playbookId }, config) => apiGet(`/v1/agent/playbooks/${encodeURIComponent(playbookId)}`, void 0, config)
|
|
4575
|
+
}),
|
|
4576
|
+
defineTool({
|
|
4577
|
+
name: "list_agent_playbook_templates",
|
|
4578
|
+
description: "List the playbook templates available to start from. Requires the agent:read scope and the Business plan.",
|
|
4579
|
+
inputSchema: { type: "object", properties: {} },
|
|
4580
|
+
argsSchema: external_exports.object({}),
|
|
4581
|
+
handler: async (_args, config) => apiGet("/v1/agent/playbooks/templates", void 0, config)
|
|
4582
|
+
}),
|
|
4583
|
+
// ── Monitorización ─────────────────────────────────────────
|
|
4584
|
+
defineTool({
|
|
4585
|
+
name: "list_monitors",
|
|
4586
|
+
description: 'List uptime and health monitors (HTTP endpoints, health contracts, cron heartbeats, cloud resources) with their current state, last result and 30-day availability. This answers "what is down right now". States: up; suspect and confirming (still being confirmed from a second region, not an outage yet); down; recovering (still counts as down). Requires the monitoring:read scope and the Pro plan or above.',
|
|
4587
|
+
inputSchema: objectWith({
|
|
4588
|
+
pinned: { type: "boolean", description: "Only the monitors pinned to the dashboard (optional)." },
|
|
4589
|
+
clientId: { ...CLIENT_ID, description: "Only the monitors of one managed client (optional)." }
|
|
4590
|
+
}),
|
|
4591
|
+
argsSchema: external_exports.object({ pinned: external_exports.boolean().optional(), clientId: external_exports.string().min(1).optional() }),
|
|
4592
|
+
handler: async ({ pinned, clientId: clientId2 }, config) => apiGet("/v1/monitoring/monitors", { pinned: pinned ? "true" : void 0, clientId: clientId2 }, config)
|
|
4593
|
+
}),
|
|
4594
|
+
defineTool({
|
|
4595
|
+
name: "get_monitor",
|
|
4596
|
+
description: "Get one monitor with its definition, current state, since when, and last result (outcome, reason code, status code, latency). Requires the monitoring:read scope and the Pro plan or above.",
|
|
4597
|
+
inputSchema: objectWith({ monitorId: MONITOR_ID }, ["monitorId"]),
|
|
4598
|
+
argsSchema: external_exports.object({ monitorId: external_exports.string().min(1) }),
|
|
4599
|
+
handler: async ({ monitorId }, config) => apiGet(`/v1/monitoring/monitors/${encodeURIComponent(monitorId)}`, void 0, config)
|
|
4600
|
+
}),
|
|
4601
|
+
defineTool({
|
|
4602
|
+
name: "list_monitor_results",
|
|
4603
|
+
description: 'List the individual check results of one monitor, newest first, kept for 90 days. Use it to find when an outage started and what each failed check returned. Paginated: pass the returned "next" as "before". Requires the monitoring:read scope and the Pro plan or above.',
|
|
4604
|
+
inputSchema: objectWith(
|
|
4605
|
+
{
|
|
4606
|
+
monitorId: MONITOR_ID,
|
|
4607
|
+
limit: { type: "integer", minimum: 1, maximum: 200, description: "Page size (default 100)." },
|
|
4608
|
+
before: { type: "string", description: 'The "next" value of the previous page (optional).' }
|
|
4609
|
+
},
|
|
4610
|
+
["monitorId"]
|
|
4611
|
+
),
|
|
4612
|
+
argsSchema: external_exports.object({ monitorId: external_exports.string().min(1), limit: external_exports.number().int().min(1).max(200).optional(), before: external_exports.string().min(1).optional() }),
|
|
4613
|
+
handler: async ({ monitorId, limit, before }, config) => apiGet(`/v1/monitoring/monitors/${encodeURIComponent(monitorId)}/results`, { limit: asText(limit), before }, config)
|
|
4614
|
+
}),
|
|
4615
|
+
defineTool({
|
|
4616
|
+
name: "get_monitor_uptime",
|
|
4617
|
+
description: "Get the daily summaries of one monitor (checks, failures, downtime, p50/p95 latency) and its availability over that period. Days close at 00:00 UTC; today is not included. Requires the monitoring:read scope and the Pro plan or above.",
|
|
4618
|
+
inputSchema: objectWith(
|
|
4619
|
+
{ monitorId: MONITOR_ID, days: { type: "integer", minimum: 1, maximum: 90, description: "How many closed days (1-90, default 30)." } },
|
|
4620
|
+
["monitorId"]
|
|
4621
|
+
),
|
|
4622
|
+
argsSchema: external_exports.object({ monitorId: external_exports.string().min(1), days: external_exports.number().int().min(1).max(90).optional() }),
|
|
4623
|
+
handler: async ({ monitorId, days }, config) => apiGet(`/v1/monitoring/monitors/${encodeURIComponent(monitorId)}/days`, { days: asText(days) }, config)
|
|
4624
|
+
}),
|
|
4625
|
+
defineTool({
|
|
4626
|
+
name: "list_monitoring_services",
|
|
4627
|
+
description: 'List the services (groups of monitors and other services, e.g. "Checkout") with their computed status (pass, warn, fail) and the components that cause it. Requires the monitoring:read scope and the Pro plan or above.',
|
|
4628
|
+
inputSchema: { type: "object", properties: {} },
|
|
4629
|
+
argsSchema: external_exports.object({}),
|
|
4630
|
+
handler: async (_args, config) => apiGet("/v1/monitoring/services", void 0, config)
|
|
4631
|
+
}),
|
|
4632
|
+
defineTool({
|
|
4633
|
+
name: "get_monitoring_service",
|
|
4634
|
+
description: "Get one service with its status, its components (monitors and services it depends on) and the culprits when it is not healthy. Requires the monitoring:read scope and the Pro plan or above.",
|
|
4635
|
+
inputSchema: objectWith({ serviceId: SERVICE_ID }, ["serviceId"]),
|
|
4636
|
+
argsSchema: external_exports.object({ serviceId: external_exports.string().min(1) }),
|
|
4637
|
+
handler: async ({ serviceId }, config) => apiGet(`/v1/monitoring/services/${encodeURIComponent(serviceId)}`, void 0, config)
|
|
4638
|
+
}),
|
|
4639
|
+
defineTool({
|
|
4640
|
+
name: "get_service_history",
|
|
4641
|
+
description: 'Get the status changes of one service, newest first, each with the components that caused it, kept for 90 days. This answers "what took the checkout down yesterday". Requires the monitoring:read scope and the Pro plan or above.',
|
|
4642
|
+
inputSchema: objectWith(
|
|
4643
|
+
{ serviceId: SERVICE_ID, limit: { type: "integer", minimum: 1, maximum: 200, description: "How many changes (default 50)." } },
|
|
4644
|
+
["serviceId"]
|
|
4645
|
+
),
|
|
4646
|
+
argsSchema: external_exports.object({ serviceId: external_exports.string().min(1), limit: external_exports.number().int().min(1).max(200).optional() }),
|
|
4647
|
+
handler: async ({ serviceId, limit }, config) => apiGet(`/v1/monitoring/services/${encodeURIComponent(serviceId)}/history`, { limit: asText(limit) }, config)
|
|
4361
4648
|
})
|
|
4362
4649
|
];
|
|
4363
4650
|
function findTool(name) {
|
|
@@ -4366,7 +4653,7 @@ function findTool(name) {
|
|
|
4366
4653
|
|
|
4367
4654
|
// src/protocol.ts
|
|
4368
4655
|
var SERVER_NAME = "aaa-sentinel-mcp";
|
|
4369
|
-
var SERVER_VERSION = "0.
|
|
4656
|
+
var SERVER_VERSION = "0.3.0";
|
|
4370
4657
|
var SUPPORTED_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
4371
4658
|
var PARSE_ERROR = -32700;
|
|
4372
4659
|
var INVALID_REQUEST = -32600;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aaa-sentinel/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Read-only MCP server for AAA Sentinel: query
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
7
7
|
"bin": {
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
"mcp",
|
|
15
15
|
"modelcontextprotocol",
|
|
16
16
|
"finops",
|
|
17
|
-
"cost"
|
|
17
|
+
"cost",
|
|
18
|
+
"monitoring",
|
|
19
|
+
"uptime",
|
|
20
|
+
"security",
|
|
21
|
+
"ai-spend"
|
|
18
22
|
],
|
|
19
23
|
"publishConfig": {
|
|
20
24
|
"access": "public"
|