sample-aws-pricing-calculator-mcp 1.3.2 → 1.3.3
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 +22 -8
- package/catalog/services/amazonRDSForSQLServer.json +72 -0
- package/dist/mcp-server.js +76 -68
- package/mcp-server.js +75 -5
- 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` hydrates a saved estimate in a headless browser to return the calculator's actual monthly cost; uses an on-demand Playwright/Chromium dependency that is 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` | Hydrate a saved estimate (by URL or ID) in a headless browser and return the calculator-computed monthly cost plus per-service rows. 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. |
|
|
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 DOM scrape of the calculator's rendered cost (eval oracle)
|
|
112
|
+
dom-cost.js # Playwright DOM scrape of the calculator's rendered cost (backs get_estimate_cost + the 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,19 @@ 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` hydrates a saved estimate (by URL or ID) in headless Chromium and reads the calculator's rendered cost — the summary monthly cost plus per-service rows. The summary `monthly_cost` is authoritative; a per-row value can render stale/$0 until the calculator recomputes, so when the per-row total disagrees the response includes a `note` and you should not attribute per-row costs.
|
|
230
|
+
|
|
231
|
+
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:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npm install playwright # if the library itself is missing
|
|
235
|
+
npx playwright install chromium # downloads the ~150MB browser binary
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Every other tool works without Playwright.
|
|
239
|
+
|
|
225
240
|
## Environment Variables
|
|
226
241
|
|
|
227
242
|
All optional. The full set is also documented machine-readably in `dist/bundle-contract.json` after build.
|
|
@@ -319,7 +334,7 @@ The cost-oracle sweep saves a fresh estimate from each verified entry's `minimal
|
|
|
319
334
|
|
|
320
335
|
### Catalog quality
|
|
321
336
|
|
|
322
|
-
The
|
|
337
|
+
The catalog content was audited along three independent axes before release.
|
|
323
338
|
|
|
324
339
|
**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
340
|
|
|
@@ -341,8 +356,7 @@ The trap audit and earns-place data are summarized here for transparency; the de
|
|
|
341
356
|
- Callers must use the correct AWS field IDs — discover them via `get_service_fields`.
|
|
342
357
|
- The server discovers applicable selector values but cannot resolve cross-field dependencies (e.g. EC2 Instance Types ↔ License).
|
|
343
358
|
- 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.
|
|
359
|
+
- 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
360
|
- 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
361
|
|
|
348
362
|
## Security
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
"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' } }.",
|
|
12
|
+
"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')."
|
|
13
|
+
],
|
|
14
|
+
"defaultFields": {
|
|
15
|
+
"gp3Iops": {
|
|
16
|
+
"value": "3000"
|
|
17
|
+
},
|
|
18
|
+
"gp3Throughput": {
|
|
19
|
+
"value": "125",
|
|
20
|
+
"unit": "mbps"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"minimalConfig": {
|
|
24
|
+
"region": "ap-northeast-1",
|
|
25
|
+
"description": "Single-AZ db.t3.small, Express, License included, gp3 storage",
|
|
26
|
+
"columnFormIPM": {
|
|
27
|
+
"value": [
|
|
28
|
+
{
|
|
29
|
+
"Number of Nodes": {
|
|
30
|
+
"value": "1"
|
|
31
|
+
},
|
|
32
|
+
"Instance Type": {
|
|
33
|
+
"value": "db.t3.small"
|
|
34
|
+
},
|
|
35
|
+
"undefined": {
|
|
36
|
+
"value": {
|
|
37
|
+
"unit": "100",
|
|
38
|
+
"selectedId": "%Utilized/Month"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"Deployment Option": {
|
|
42
|
+
"value": "Single-AZ"
|
|
43
|
+
},
|
|
44
|
+
"License Model": {
|
|
45
|
+
"value": "License included"
|
|
46
|
+
},
|
|
47
|
+
"Database Edition": {
|
|
48
|
+
"value": "Express"
|
|
49
|
+
},
|
|
50
|
+
"TermType": {
|
|
51
|
+
"value": "OnDemand"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"optimize": "0",
|
|
57
|
+
"createRDSProxy": "0",
|
|
58
|
+
"storageType": "General Purpose-GP3",
|
|
59
|
+
"storageAmount": {
|
|
60
|
+
"value": "20",
|
|
61
|
+
"unit": "gb|NA"
|
|
62
|
+
},
|
|
63
|
+
"gp3Iops": "3000",
|
|
64
|
+
"gp3Throughput": {
|
|
65
|
+
"value": "125",
|
|
66
|
+
"unit": "mbps"
|
|
67
|
+
},
|
|
68
|
+
"DatabaseInsightsSelected": "0"
|
|
69
|
+
},
|
|
70
|
+
"lastVerifiedAt": "2026-10-09",
|
|
71
|
+
"verifiedEstimateId": "375fbb2ea95a5bcd2bd73b49cb8706a8f4c7bea5"
|
|
72
|
+
}
|