@aaa-sentinel/mcp-server 0.0.0-stage → 0.2.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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -3
  3. package/dist/cli.js +4505 -0
  4. package/package.json +41 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AAA Sentinel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,167 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @aaa-sentinel/mcp-server
2
+
3
+ Lets an AI assistant read your cloud cost data — accounts, scans, findings, savings and
4
+ chargeback — through the [Model Context Protocol](https://modelcontextprotocol.io), so you can
5
+ ask *"which of my AWS accounts is bleeding the most money this month, and why"* in the chat
6
+ window you already have open instead of a dashboard you have to remember to visit.
7
+
8
+ > **User** — Which account has the most waste right now?
9
+ >
10
+ > **Assistant** *(calls `list_accounts`, then `get_reports_summary`, then `list_findings`)* —
11
+ > `prod-eu-west-1` accounts for $4,180/mo of the $9,240 total, and $1,730 of that is recoverable:
12
+ > 11 unattached EBS volumes ($412/mo), 3 idle RDS instances ($980/mo) and an over-provisioned
13
+ > NAT gateway ($338/mo).
14
+
15
+ ## Requirements
16
+
17
+ - Node.js 20 or newer.
18
+ - An OAuth2 application created in the [developer portal](https://app.aaa-sentinel.com/developer/apps).
19
+ - Scopes depend on what you want the assistant to be able to read — see the table below. Grant
20
+ only those; the scopes you leave out are simply not reachable from the assistant.
21
+ - A **Pro** plan for `get_reports_summary`, `list_savings`, `get_dashboard`, `get_cost_forecast`
22
+ and the security tools (which also need the security add-on on the account), **Business** for
23
+ `get_chargeback` and `list_cost_anomalies`. The other tools work on any paid plan.
24
+
25
+ ## Configuration
26
+
27
+ The server speaks stdio: your MCP client launches it as a child process and keeps it alive. All
28
+ clients use the same shape of configuration file.
29
+
30
+ **Claude Desktop** — `claude_desktop_config.json`
31
+ (`%APPDATA%\Claude` on Windows, `~/Library/Application Support/Claude` on macOS):
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "aaa-sentinel": {
37
+ "command": "npx",
38
+ "args": ["--yes", "@aaa-sentinel/mcp-server"],
39
+ "env": {
40
+ "AAA_SENTINEL_MCP_CLIENT_ID": "your-client-id",
41
+ "AAA_SENTINEL_MCP_CLIENT_SECRET": "your-client-secret"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ **VS Code** — `.vscode/mcp.json`, using an input so the secret is never written to a file that
49
+ could be committed:
50
+
51
+ ```json
52
+ {
53
+ "inputs": [
54
+ { "id": "sentinel-secret", "type": "promptString", "description": "AAA Sentinel client secret", "password": true }
55
+ ],
56
+ "servers": {
57
+ "aaa-sentinel": {
58
+ "type": "stdio",
59
+ "command": "npx",
60
+ "args": ["--yes", "@aaa-sentinel/mcp-server"],
61
+ "env": {
62
+ "AAA_SENTINEL_MCP_CLIENT_ID": "your-client-id",
63
+ "AAA_SENTINEL_MCP_CLIENT_SECRET": "${input:sentinel-secret}"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ | Variable | Required | Meaning |
71
+ | --- | --- | --- |
72
+ | `AAA_SENTINEL_MCP_CLIENT_ID` | yes | Client ID of the OAuth2 application |
73
+ | `AAA_SENTINEL_MCP_CLIENT_SECRET` | yes | Client secret. Treat it as a password |
74
+ | `AAA_SENTINEL_MCP_BASE_URL` | no | Defaults to `https://api.aaa-sentinel.com`. Must be `https` — the secret is never sent over plain HTTP |
75
+ | `AAA_SENTINEL_MCP_DEBUG` | no | Set to `1` to print one line to stderr per tool call with the number of API requests used so far. Off by default |
76
+
77
+ If a credential is missing or the base URL is not `https`, the process prints one line to
78
+ **stderr** and exits with code 1. It does not start half-configured: a client that believes it is
79
+ connected to a server that can answer nothing is worse than a client that reports a failure.
80
+
81
+ ## Tools
82
+
83
+ All fourteen are **read-only**.
84
+
85
+ | Tool | Arguments | Scope | Plan |
86
+ | --- | --- | --- | --- |
87
+ | `list_accounts` | — | `accounts:read` | any |
88
+ | `list_scans` | `accountId` | `scans:read` | any |
89
+ | `get_scan` | `scanId` | `scans:read` | any |
90
+ | `list_findings` | `scanId`, `includeSuppressed?` | `findings:read` | any |
91
+ | `get_reports_summary` | `accountId?` | `reports:read` | Pro |
92
+ | `list_savings` | `accountId?`, `type?` | `savings:read` | Pro |
93
+ | `get_chargeback` | `clientId?` | `reports:read` | Business |
94
+ | `get_dashboard` | `accountId?` | `dashboard:read` | Pro |
95
+ | `get_cost_forecast` | `accountId` | `reports:read` | Pro |
96
+ | `list_cost_anomalies` | `accountId?` | `reports:read` | Business |
97
+ | `get_security_overview` | — | `security:read` | Pro + security add-on |
98
+ | `get_security_score` | `accountId` | `security:read` | Pro + security add-on |
99
+ | `list_security_findings` | `accountId`, `source?` | `security:read` | Pro + security add-on |
100
+ | `get_security_conformance` | `accountId` or `clientId` | `security:read` (+ `reports:read` for `clientId`) | Pro (Business for `clientId`) |
101
+
102
+ `type` is one of `compute`, `storage`, `network`, `database`, `serverless`, `governance`.
103
+ `source` is one of `own`, `corroborated`, `securityhub`, `guardduty`, `defender`, `scc`.
104
+
105
+ The security tools need the security add-on enabled on the account (20 €/month per account).
106
+ Without it they answer with `access: "teaser"` and no scan data, so the assistant can tell
107
+ "not enabled" apart from "nothing found".
108
+
109
+ ### Why there is nothing that writes
110
+
111
+ There is no tool to approve a remediation, launch a playbook, stop an instance, start a security
112
+ scan or enable the (billed) security add-on, and that is a
113
+ decision rather than a gap. An MCP server with write access puts a model — with its own idea of
114
+ what is convenient, and a prompt an attacker may have influenced — inside the path that changes
115
+ your infrastructure. Execution stays in the product, where it is gated by approvals, dry runs and
116
+ an audit trail. The assistant reads and reasons; it does not act.
117
+
118
+ The same reasoning applies to the scopes: an OAuth2 application registered with only
119
+ `accounts:read` and `findings:read` cannot be talked into doing anything else, no matter what the
120
+ conversation contains.
121
+
122
+ ## Rate limits and quota
123
+
124
+ Calls made through this server count against the same monthly quota and per-minute burst limit as
125
+ any other API client, and they are billed to the same plan. An assistant that loops over every
126
+ account calling `list_findings` will consume quota quickly — the usage page in the portal shows
127
+ the consumption per application, so keep this server on its own OAuth2 application if you want to
128
+ be able to tell its traffic apart from your CI's.
129
+
130
+ The server holds a single access token in memory, refreshes it a minute before it expires, and
131
+ serialises concurrent refreshes into one request. Every tool costs exactly one API request — none
132
+ of them paginates or fans out — so the burst limit maps directly to tool calls per minute. `429`
133
+ and `5xx` responses are retried with backoff, honouring `Retry-After` unless the server asks for
134
+ more than 10 seconds; when it asks for longer, the error carries the wait so the assistant can
135
+ tell you instead of retrying blindly.
136
+
137
+ What the numbers above do **not** tell you is how many tools your assistant chains together to
138
+ answer one question — that is decided by the model, not by us, and it is the multiplier that
139
+ decides whether the limit is comfortable. Set `AAA_SENTINEL_MCP_DEBUG=1`, ask a few of your real
140
+ questions, and read the running count from your client's MCP log:
141
+
142
+ ```
143
+ [mcp] list_accounts — API requests: 1 in the last 60s, 1 total (tokens: 1)
144
+ [mcp] list_findings — API requests: 2 in the last 60s, 2 total (tokens: 1)
145
+ ```
146
+
147
+ The first number is the one to watch: it is counted over a rolling minute, which is the same
148
+ unit as the burst limit, so you can compare it with your plan without doing arithmetic.
149
+
150
+ ## Troubleshooting
151
+
152
+ **The client shows the server as failed and there is no output.** Look at your client's MCP log,
153
+ not at stdout: stdout carries only protocol messages, so every diagnostic goes to stderr. The
154
+ usual cause is a missing `AAA_SENTINEL_MCP_CLIENT_ID` or `AAA_SENTINEL_MCP_CLIENT_SECRET`.
155
+
156
+ **Tools appear but every call answers with an error mentioning HTTP 403.** The OAuth2 application
157
+ does not have the scope that tool needs, or your plan does not include it. Scopes are fixed when
158
+ the application is created — register a new one rather than trying to widen the old one.
159
+
160
+ **A tool answers with HTTP 429.** You reached the per-minute burst limit of your plan. The error
161
+ states how many seconds are left; it clears on its own, and asking the assistant to work over
162
+ fewer accounts at a time is usually enough.
163
+
164
+ ## License
165
+
166
+ MIT — see [LICENSE](LICENSE). The licence covers this client only; access to the API is governed by
167
+ the terms of service at <https://app.aaa-sentinel.com>.