sample-aws-pricing-calculator-mcp 1.3.2 → 1.3.4
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 +27 -8
- package/catalog/services/amazonRDSForSQLServer.json +73 -0
- package/dist/mcp-server.js +76 -64
- package/mcp-server.js +88 -6
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
- **Build estimates from natural language** - agent constructs the estimate via MCP tools; the server saves it to AWS Pricing Calculator and returns a shareable URL.
|
|
10
10
|
- **No AWS credentials required** - uses public, unauthenticated calculator.aws CDN endpoints.
|
|
11
11
|
- **Live service definitions** - fetches the AWS Pricing Calculator manifest at runtime (~436 services).
|
|
12
|
-
- **Verified Configs Catalog** -
|
|
12
|
+
- **Verified Configs Catalog** - 21 per-service entries declaring the smallest config that produces a priced estimate, with documented gotchas.
|
|
13
13
|
- **Lint refusal before save** - refuses estimates the calculator would render read-only or required-input, with actionable recovery hints.
|
|
14
14
|
- **Import existing estimates** - download by URL or ID as JSON (for region swaps, modifications) or Markdown (for LLM analysis).
|
|
15
|
+
- **Read computed costs** - `get_estimate_cost` re-shares an estimate through the calculator (Update estimate → Share) so AWS persists the computed costs, then reads them back: upfront, monthly, and 12-month totals, the pricing date, and every per-line cost. Uses an on-demand Playwright/Chromium dependency only needed for this tool.
|
|
15
16
|
- **Two transport modes** - stdio (default, for local clients like Claude Desktop, Kiro, Cursor) and optional HTTP (`MCP_TRANSPORT=http`) for hosted deployments.
|
|
16
17
|
|
|
17
18
|
## Example
|
|
@@ -70,19 +71,20 @@ Then point your client at the built bundle:
|
|
|
70
71
|
| Tool | Description |
|
|
71
72
|
|---|---|
|
|
72
73
|
| `search_services` | Search AWS services by name or key. Supports comma-separated queries. |
|
|
73
|
-
| `get_service_fields` | Get input field IDs, types, labels, valid options, and selector values for one or more services. For curated services, the response includes a `catalog` block (`minimalConfig`, required-field hints, traps). For deprecated parent service codes (currently `amazonS3`), returns a `redirect_to_parent` status with `child_service_codes` listing the actual service codes to use instead. |
|
|
74
|
+
| `get_service_fields` | Get input field IDs, types, labels, valid options, and selector values for one or more services. For curated services, the response includes a `catalog` block (`minimalConfig`, required-field hints, traps). For deprecated parent service codes (currently `amazonS3`), returns a `redirect_to_parent` status with `child_service_codes` listing the actual service codes to use instead. Services with an include/exclude AWS Free Tier template pair (e.g. Lambda) return a `freeTierChoice` block so the caller can ask the user and pass the chosen template as `estimateFor`. |
|
|
74
75
|
| `create_estimate` | Create a new empty estimate. Returns an estimate ID. |
|
|
75
|
-
| `add_service` | Add one or more services to an estimate. Validates field IDs and values against the live service definition (dropdowns, fileSize unit format, numeric/frequency types, region whitelist). Auto-corrects unambiguous mistakes (case mismatches, typos, number-to-string coercion) and returns a `corrections` array on the per-service result. Partial entries return a `partial: true` warning when required inputs are missing. |
|
|
76
|
+
| `add_service` | Add one or more services to an estimate. Validates field IDs and values against the live service definition (dropdowns, fileSize unit format, numeric/frequency types, region whitelist). Auto-corrects unambiguous mistakes (case mismatches, typos, number-to-string coercion) and returns a `corrections` array on the per-service result. Partial entries return a `partial: true` warning when required inputs are missing. A per-entry `estimateFor` selects a specific pricing template (e.g. `lambdaWithoutFreeTier` to exclude the AWS Free Tier); Free-Tier-capable services added without a choice return a `free_tier_choice` advisory. |
|
|
76
77
|
| `validate_estimate` | Dry-run preflight: builds the would-be saved payload and runs a static check, without calling the save API. Returns `{lint_verdict, next_step, lint_services, would_be_payload}`. Use to confirm an estimate would render correctly before saving. |
|
|
77
78
|
| `build_estimate` | One-shot create + add services + lint preflight + save. Returns the shareable URL on success, or a structured envelope identifying which services need field discovery before retry. |
|
|
78
79
|
| `export_estimate` | Save the in-flight estimate to calculator.aws and return a shareable URL. Refuses with an actionable `next_step` if the static linter predicts the saved blob would rehydrate read-only. |
|
|
79
80
|
| `import_estimate` | Download an existing estimate by URL or ID. Returns JSON (raw) or Markdown. |
|
|
81
|
+
| `get_estimate_cost` | Return the AWS-computed cost of a saved estimate (by URL or ID): upfront, monthly, and 12-month totals, the pricing date, and every per-line cost (complete, un-paginated). It re-shares the estimate through the calculator (Update estimate → Share) so AWS persists the costs, then reads them back — this saves a fresh copy under a new id (`priced_estimate_url`; the original is untouched). Requires Playwright and the Chromium browser — an on-demand dependency NOT installed by default; when either is missing the tool returns `cost_available:false` with the exact install commands instead of failing. **Runs only on an explicit user request for the cost — agents should not call it automatically after `export_estimate`/`build_estimate`.** |
|
|
80
82
|
| `get_server_info` | Return version and capability information. |
|
|
81
83
|
|
|
82
84
|
## Project Structure
|
|
83
85
|
|
|
84
86
|
```
|
|
85
|
-
mcp-server.js # Entry point — registers the
|
|
87
|
+
mcp-server.js # Entry point — registers the 10 MCP tools, stdio + HTTP transports
|
|
86
88
|
lib/
|
|
87
89
|
aws/ # AWS API access + payload construction
|
|
88
90
|
aws-client.js # Manifest loading, service definitions, save/read APIs, selector aggregations
|
|
@@ -107,7 +109,7 @@ lib/
|
|
|
107
109
|
store/ # In-flight estimate persistence
|
|
108
110
|
estimate-store.js # Pluggable store (memory default)
|
|
109
111
|
estimate-store-dynamodb.js # DynamoDB-backed store for stateless multi-replica deployments
|
|
110
|
-
dom-cost.js # Playwright
|
|
112
|
+
dom-cost.js # Playwright flows: re-share for computed costs (get_estimate_cost) + single-page DOM read (eval oracle). Playwright/Chromium is an on-demand dependency
|
|
111
113
|
catalog/
|
|
112
114
|
schema.json # JSON Schema for catalog entries
|
|
113
115
|
services/ # Verified configs catalog (minimalConfig, traps, subServices)
|
|
@@ -222,6 +224,24 @@ When `export_estimate` is called, the server:
|
|
|
222
224
|
|
|
223
225
|
AWS recalculates the actual costs when someone opens the link.
|
|
224
226
|
|
|
227
|
+
### Reading computed costs
|
|
228
|
+
|
|
229
|
+
`get_estimate_cost` returns AWS's computed cost for a saved estimate (by URL or ID). Because the calculator prices in the browser, the tool re-shares the estimate through the UI — it presses **Update estimate** (recompute to current pricing) then **Share**, which makes AWS persist the costs — and then reads the resulting saved estimate via the public read API. The response carries `upfront_cost`, `monthly_cost`, `total_12_months_cost` (derived as upfront + 12×monthly, which is how the calculator defines the 12-month total), `pricing_as_of`, and `rows` — every group/line with its own monthly, upfront, and config. There is no pagination, so `rows_complete` is always true.
|
|
230
|
+
|
|
231
|
+
Because it carries an optional, heavyweight dependency (Playwright + Chromium, not installed by default), `get_estimate_cost` is meant to run **only when the user explicitly asks for the computed cost**. Agents should not invoke it automatically after `export_estimate` or `build_estimate` — those already return the shareable URL, which is the normal end of the flow.
|
|
232
|
+
|
|
233
|
+
Because Update+Share re-saves, the tool creates a **fresh copy under a new id** (returned as `priced_estimate_url`); the original estimate is unchanged. This avoids two dead ends we ruled out: scraping the rendered table (it paginates at 10 rows) and the Export→file download (which does not fire in headless Chromium).
|
|
234
|
+
|
|
235
|
+
This is the only part of the server that needs a browser. **Playwright and the Chromium binary are an on-demand dependency, not installed by default.** The tool checks for them first and, when either is missing, returns `cost_available:false` with the exact install commands rather than failing:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npm install playwright # if the library itself is missing
|
|
239
|
+
npx playwright install chromium # downloads the ~150MB browser binary
|
|
240
|
+
npx playwright install-deps chromium # installs system dependencies
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Every other tool works without Playwright.
|
|
244
|
+
|
|
225
245
|
## Environment Variables
|
|
226
246
|
|
|
227
247
|
All optional. The full set is also documented machine-readably in `dist/bundle-contract.json` after build.
|
|
@@ -319,7 +339,7 @@ The cost-oracle sweep saves a fresh estimate from each verified entry's `minimal
|
|
|
319
339
|
|
|
320
340
|
### Catalog quality
|
|
321
341
|
|
|
322
|
-
The
|
|
342
|
+
The catalog content was audited along three independent axes before release.
|
|
323
343
|
|
|
324
344
|
**Cost-rendering correctness (deterministic).** The `validate-catalog:cost` sweep saves each of the verified entries' `minimalConfig` and confirms a non-zero rendered cost via the DOM oracle. Result: **entries render priced cost** (e.g. Lambda $699.80/mo, RDS PostgreSQL $175.75/mo, EC2 $70.08/mo).
|
|
325
345
|
|
|
@@ -341,8 +361,7 @@ The trap audit and earns-place data are summarized here for transparency; the de
|
|
|
341
361
|
- Callers must use the correct AWS field IDs — discover them via `get_service_fields`.
|
|
342
362
|
- The server discovers applicable selector values but cannot resolve cross-field dependencies (e.g. EC2 Instance Types ↔ License).
|
|
343
363
|
- With the default `memory` store, in-flight estimates don't persist across restarts. Use `ESTIMATES_STORE=dynamodb` for stateless or multi-replica deployments.
|
|
344
|
-
- No local cost calculation — pricing is computed by AWS
|
|
345
|
-
- Only `https://calculator.aws/` is supported.
|
|
364
|
+
- No local cost calculation — pricing is computed by AWS. View the shareable link (press **Update estimate** in the calculator UI to reflect the latest pricing), or call `get_estimate_cost` to read the computed cost programmatically (requires the on-demand Playwright/Chromium dependency).
|
|
346
365
|
- Catalog coverage is partial (verified entries against ~436 manifest services). Uncatalogued services still benefit from the lint and trace events; they just don't get the magnitude-calibration role the catalog plays.
|
|
347
366
|
|
|
348
367
|
## Security
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schema.json",
|
|
3
|
+
"serviceCode": "amazonRDSForSQLServer",
|
|
4
|
+
"displayName": "Amazon RDS for SQL Server",
|
|
5
|
+
"templateId": "rdsForOracle",
|
|
6
|
+
"status": "verified",
|
|
7
|
+
"traps": [
|
|
8
|
+
"The template id for RDS for SQL Server is literally 'rdsForOracle' — this is a shared/legacy template id the calculator reuses across RDS engines, NOT a mis-mapping. A saved SQL Server estimate correctly carries estimateFor: 'rdsForOracle'; the pricing engine selects the SQL Server rate card from serviceCode + the columnFormIPM mappingDefinitionName 'rds-sqlserver-calc', not from the template id.",
|
|
9
|
+
"GP3 storage silently requires companion fields. When storageType is 'General Purpose-GP3' the calculator ALWAYS emits gp3Iops (baseline 3000) and gp3Throughput (baseline 125 MiBps). The manifest does NOT mark them validations.required, so get_service_fields doesn't flag them and the lint can't refuse without them — but omitting them makes the pricing engine charge for (0 - 3000) IOPS and (0 - 125) MiBps, driving the whole estimate NEGATIVE (issue #44: a db.t3.small Single-AZ Express estimate rendered -35.98 USD instead of 48.02 USD). These are injected automatically via defaultFields; keep them present. Injecting them when a non-GP3 storage type is selected is harmless — the engine ignores them.",
|
|
10
|
+
"Provisioned IOPS storage has its own companions: storageType 'Provisioned IOPS' (io1) needs provisioningIOPS, and 'Provisioned IOPS-IO2' (io2) needs provisionedIOPSIO2 (both baseline 1000). If you switch storageType to io1/io2, supply the matching IOPS field or the storage line will mis-price for the same reason GP3 does.",
|
|
11
|
+
"'Unbundled Licensing' is a dependent columnFormIPM cell fixed by instance class: it is TRUE for 7th-generation+ instances (m7i, r7i, r8i, x2m, ...) and FALSE for older ones, with no instance offering both (per the selector aggregations). Omitting it on a 7th-gen instance makes a directly-saved estimate silently drop the entire SQL Server/Windows licence (roughly halving the price), even though the calculator's edit view auto-selects it. The lint REFUSES to save a row that omits it when the aggregations pin it to a single value, and tells you the exact value to add (issue #48) — set e.g. {\"Unbundled Licensing\": {\"value\": \"TRUE\"}} in the row for a 7th-gen instance, FALSE for older ones.",
|
|
12
|
+
"Instance configuration uses a columnFormIPM matrix — send the WRAPPED shape, NOT dotted-path keys. Shape: { columnFormIPM: { value: [{ <selectorId>: { value: '<n>' }, ... }] } }. Selector ids: 'Number of Nodes', 'Instance Type', 'Deployment Option', 'License Model', 'Database Edition', 'TermType', 'LeaseContractLength', 'PurchaseOption', 'Unbundled Licensing'. The literal string 'undefined' is the utilization slot key, and its inner value is itself an object: { value: { unit: '<percent>', selectedId: '%Utilized/Month' } }.",
|
|
13
|
+
"storageType options: 'General Purpose' (gp2), 'General Purpose-GP3' (gp3), 'Provisioned IOPS' (io1), 'Provisioned IOPS-IO2' (io2), 'Magnetic'. Note the field id is 'storageType' for SQL Server (RDS for PostgreSQL uses 'storageVolume')."
|
|
14
|
+
],
|
|
15
|
+
"defaultFields": {
|
|
16
|
+
"gp3Iops": {
|
|
17
|
+
"value": "3000"
|
|
18
|
+
},
|
|
19
|
+
"gp3Throughput": {
|
|
20
|
+
"value": "125",
|
|
21
|
+
"unit": "mbps"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"minimalConfig": {
|
|
25
|
+
"region": "ap-northeast-1",
|
|
26
|
+
"description": "Single-AZ db.t3.small, Express, License included, gp3 storage",
|
|
27
|
+
"columnFormIPM": {
|
|
28
|
+
"value": [
|
|
29
|
+
{
|
|
30
|
+
"Number of Nodes": {
|
|
31
|
+
"value": "1"
|
|
32
|
+
},
|
|
33
|
+
"Instance Type": {
|
|
34
|
+
"value": "db.t3.small"
|
|
35
|
+
},
|
|
36
|
+
"undefined": {
|
|
37
|
+
"value": {
|
|
38
|
+
"unit": "100",
|
|
39
|
+
"selectedId": "%Utilized/Month"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"Deployment Option": {
|
|
43
|
+
"value": "Single-AZ"
|
|
44
|
+
},
|
|
45
|
+
"License Model": {
|
|
46
|
+
"value": "License included"
|
|
47
|
+
},
|
|
48
|
+
"Database Edition": {
|
|
49
|
+
"value": "Express"
|
|
50
|
+
},
|
|
51
|
+
"TermType": {
|
|
52
|
+
"value": "OnDemand"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"optimize": "0",
|
|
58
|
+
"createRDSProxy": "0",
|
|
59
|
+
"storageType": "General Purpose-GP3",
|
|
60
|
+
"storageAmount": {
|
|
61
|
+
"value": "20",
|
|
62
|
+
"unit": "gb|NA"
|
|
63
|
+
},
|
|
64
|
+
"gp3Iops": "3000",
|
|
65
|
+
"gp3Throughput": {
|
|
66
|
+
"value": "125",
|
|
67
|
+
"unit": "mbps"
|
|
68
|
+
},
|
|
69
|
+
"DatabaseInsightsSelected": "0"
|
|
70
|
+
},
|
|
71
|
+
"lastVerifiedAt": "2026-10-09",
|
|
72
|
+
"verifiedEstimateId": "375fbb2ea95a5bcd2bd73b49cb8706a8f4c7bea5"
|
|
73
|
+
}
|