@jadenrazo/cloudcost-mcp 0.3.0 → 0.5.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 +189 -40
- package/data/gcp-pricing/cloud-sql.json +74 -39
- package/data/gcp-pricing/cloud-storage.json +11 -6
- package/data/gcp-pricing/compute-engine.json +1175 -285
- package/data/gcp-pricing/metadata.json +1 -1
- package/data/gcp-pricing/persistent-disk.json +16 -11
- package/data/region-price-multipliers.json +62 -4
- package/data/resource-equivalents.json +154 -15
- package/dist/{chunk-EI63JCAA.js → chunk-E7KOWAMW.js} +4104 -2068
- package/dist/{chunk-XDBTEI42.js → chunk-TRRAOOVF.js} +6 -16
- package/dist/cli.js +12 -12
- package/dist/index.js +902 -42
- package/dist/{loader-INGM66QV.js → loader-VXYJYDIH.js} +2 -2
- package/package.json +31 -10
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">CloudCost MCP Server</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
Multi-cloud cost analysis for Terraform
|
|
4
|
+
Multi-cloud cost analysis for Terraform, CloudFormation, Pulumi, and Bicep/ARM. Live pricing from AWS, Azure, and GCP.
|
|
5
5
|
<br />
|
|
6
6
|
Built on the <a href="https://modelcontextprotocol.io">Model Context Protocol</a> for seamless AI agent integration.
|
|
7
7
|
</p>
|
|
@@ -28,16 +28,30 @@
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
CloudCost MCP is a [Model Context Protocol](https://modelcontextprotocol.io)
|
|
31
|
+
CloudCost MCP is a [Model Context Protocol](https://modelcontextprotocol.io) server that lets AI agents parse infrastructure-as-code across multiple formats (Terraform, CloudFormation, Pulumi, Bicep/ARM), query real-time pricing data, and generate multi-cloud cost comparison reports. It connects directly to public pricing APIs from AWS, Azure, and GCP. No API keys or cloud credentials required.
|
|
32
32
|
|
|
33
33
|
### What it does
|
|
34
34
|
|
|
35
|
-
- Parses Terraform HCL files and
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
35
|
+
- Parses Terraform HCL files, CloudFormation templates, Pulumi stack exports, and Bicep/ARM templates with automatic format detection
|
|
36
|
+
- Extracts resource inventories with variable resolution, including referenced modules and OpenTofu `.tofu` files
|
|
37
|
+
- Queries live on-demand pricing from AWS Bulk Pricing CSV and Azure Retail Prices REST API; GCP via live Cloud Billing Catalog API with bundled fallback
|
|
38
|
+
- Maps equivalent resources across AWS, Azure, and GCP (compute, database, storage, networking, Kubernetes, container registries, secrets management, DNS)
|
|
39
|
+
- Generates cost estimates with per-resource breakdowns (monthly and yearly) across multiple currencies
|
|
40
|
+
- Compares costs across all three providers side-by-side in markdown, JSON, CSV, or FOCUS format
|
|
41
|
+
- Provides optimization recommendations: right-sizing, reserved pricing, provider switching, spot/preemptible instances
|
|
42
|
+
- Models hypothetical scenarios (instance type changes, region moves, commitment levels) without modifying Terraform files
|
|
43
|
+
- Projects costs over 3, 6, 12, and 36-month horizons with reserved instance comparisons
|
|
44
|
+
- Tags resources for cost attribution and groups report output by team, environment, or any custom label
|
|
45
|
+
- Posts cost estimate comments to pull requests via a reusable GitHub Actions composite action
|
|
46
|
+
|
|
47
|
+
### Supported IaC Formats
|
|
48
|
+
|
|
49
|
+
| Format | Extensions | Auto-detected |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| Terraform/OpenTofu | `.tf`, `.tofu` | Yes |
|
|
52
|
+
| CloudFormation | `.yaml`, `.yml`, `.json`, `.template` | Yes |
|
|
53
|
+
| Pulumi | `.json` (stack export) | Yes |
|
|
54
|
+
| Bicep/ARM | `.json` (ARM template) | Yes |
|
|
41
55
|
|
|
42
56
|
---
|
|
43
57
|
|
|
@@ -113,7 +127,7 @@ node dist/index.js
|
|
|
113
127
|
|
|
114
128
|
## Tools
|
|
115
129
|
|
|
116
|
-
The server exposes
|
|
130
|
+
The server exposes eleven MCP tools. Each accepts JSON input and returns structured JSON output.
|
|
117
131
|
|
|
118
132
|
### `analyze_terraform`
|
|
119
133
|
|
|
@@ -134,6 +148,7 @@ Calculate costs for parsed resources on a specific provider. Returns monthly and
|
|
|
134
148
|
| `tfvars` | `string` | No | Variable overrides |
|
|
135
149
|
| `provider` | `aws \| azure \| gcp` | Yes | Target provider for pricing |
|
|
136
150
|
| `region` | `string` | No | Target region (auto-mapped if omitted) |
|
|
151
|
+
| `currency` | `string` | No | Output currency (default: `USD`). Supports: USD, EUR, GBP, JPY, CAD, AUD, INR, BRL |
|
|
137
152
|
|
|
138
153
|
### `compare_providers`
|
|
139
154
|
|
|
@@ -143,8 +158,9 @@ Full pipeline: parse Terraform, map resources across providers, fetch pricing, a
|
|
|
143
158
|
|-----------|------|----------|-------------|
|
|
144
159
|
| `files` | `{path, content}[]` | Yes | Terraform files |
|
|
145
160
|
| `tfvars` | `string` | No | Variable overrides |
|
|
146
|
-
| `format` | `markdown \| json \| csv` | No | Report format (default: `markdown`) |
|
|
161
|
+
| `format` | `markdown \| json \| csv \| focus` | No | Report format (default: `markdown`) |
|
|
147
162
|
| `providers` | `string[]` | No | Providers to compare (default: all three) |
|
|
163
|
+
| `currency` | `string` | No | Output currency (default: `USD`). Supports: USD, EUR, GBP, JPY, CAD, AUD, INR, BRL |
|
|
148
164
|
|
|
149
165
|
### `get_equivalents`
|
|
150
166
|
|
|
@@ -178,6 +194,74 @@ Analyze Terraform resources and return optimization recommendations. Includes ri
|
|
|
178
194
|
| `tfvars` | `string` | No | Variable overrides |
|
|
179
195
|
| `providers` | `string[]` | No | Providers to evaluate (default: all three) |
|
|
180
196
|
|
|
197
|
+
### `what_if`
|
|
198
|
+
|
|
199
|
+
Run hypothetical pricing scenarios against existing Terraform resources. Change instance types, regions, providers, or commitment levels and see the cost delta without modifying your actual configuration.
|
|
200
|
+
|
|
201
|
+
| Parameter | Type | Required | Description |
|
|
202
|
+
|-----------|------|----------|-------------|
|
|
203
|
+
| `files` | `{path, content}[]` | Yes | Terraform files |
|
|
204
|
+
| `tfvars` | `string` | No | Variable overrides |
|
|
205
|
+
| `scenarios` | `object[]` | Yes | Changes to model. Each specifies a resource name and the attributes to override |
|
|
206
|
+
| `providers` | `string[]` | No | Providers to evaluate (default: all three) |
|
|
207
|
+
| `currency` | `string` | No | Output currency (default: `USD`) |
|
|
208
|
+
|
|
209
|
+
**Example**: model the cost impact of switching compute from on-demand to spot across providers:
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"files": [{ "path": "main.tf", "content": "..." }],
|
|
214
|
+
"scenarios": [
|
|
215
|
+
{ "resource": "aws_instance.web", "pricing_model": "spot" },
|
|
216
|
+
{ "resource": "aws_instance.app", "instance_type": "m6i.2xlarge" }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### `analyze_plan`
|
|
222
|
+
|
|
223
|
+
Parse terraform plan JSON output for before/after cost-of-change analysis. Shows what resources are being added, changed, or destroyed and the cost impact of each change.
|
|
224
|
+
|
|
225
|
+
| Parameter | Type | Required | Description |
|
|
226
|
+
|-----------|------|----------|-------------|
|
|
227
|
+
| `plan_json` | `string` | Yes | JSON output from `terraform show -json planfile` |
|
|
228
|
+
| `provider` | `aws \| azure \| gcp` | No | Target provider for pricing (auto-detected if omitted) |
|
|
229
|
+
| `currency` | `string` | No | Output currency (default: `USD`) |
|
|
230
|
+
|
|
231
|
+
### `compare_actual`
|
|
232
|
+
|
|
233
|
+
Parse `.tfstate` files to compare actual infrastructure costs vs estimates. Identifies drift between planned and deployed resources.
|
|
234
|
+
|
|
235
|
+
| Parameter | Type | Required | Description |
|
|
236
|
+
|-----------|------|----------|-------------|
|
|
237
|
+
| `state_json` | `string` | Yes | Contents of a `terraform.tfstate` file |
|
|
238
|
+
| `provider` | `aws \| azure \| gcp` | No | Target provider for pricing (auto-detected if omitted) |
|
|
239
|
+
| `currency` | `string` | No | Output currency (default: `USD`) |
|
|
240
|
+
|
|
241
|
+
### `price_trends`
|
|
242
|
+
|
|
243
|
+
Query historical pricing trends and price change tracking. Shows how pricing has changed over time for specific resource types.
|
|
244
|
+
|
|
245
|
+
| Parameter | Type | Required | Description |
|
|
246
|
+
|-----------|------|----------|-------------|
|
|
247
|
+
| `provider` | `aws \| azure \| gcp` | Yes | Cloud provider |
|
|
248
|
+
| `service` | `string` | Yes | Service category |
|
|
249
|
+
| `resource_type` | `string` | Yes | Instance type, storage type, etc. |
|
|
250
|
+
| `region` | `string` | Yes | Cloud region |
|
|
251
|
+
| `period_days` | `number` | No | Lookback period in days (default: `90`) |
|
|
252
|
+
|
|
253
|
+
### `detect_anomalies`
|
|
254
|
+
|
|
255
|
+
Cost anomaly detection with budget checks, price changes, concentration risk, and right-sizing hints. Analyzes parsed resources and flags potential cost issues.
|
|
256
|
+
|
|
257
|
+
| Parameter | Type | Required | Description |
|
|
258
|
+
|-----------|------|----------|-------------|
|
|
259
|
+
| `files` | `{path, content}[]` | Yes | IaC files to analyze |
|
|
260
|
+
| `tfvars` | `string` | No | Variable overrides |
|
|
261
|
+
| `provider` | `aws \| azure \| gcp` | No | Target provider (auto-detected if omitted) |
|
|
262
|
+
| `budget_monthly` | `number` | No | Monthly budget cap in USD |
|
|
263
|
+
| `currency` | `string` | No | Output currency (default: `USD`) |
|
|
264
|
+
|
|
181
265
|
---
|
|
182
266
|
|
|
183
267
|
## How Pricing Works
|
|
@@ -186,30 +270,32 @@ CloudCost uses a tiered approach to get the most accurate pricing available with
|
|
|
186
270
|
|
|
187
271
|
### AWS
|
|
188
272
|
|
|
189
|
-
1. **Live CSV streaming** (primary)
|
|
273
|
+
1. **Live CSV streaming** (primary). For EC2 compute pricing, the server streams the AWS Bulk Pricing CSV for the target region line-by-line. This avoids loading the full ~267 MB file into memory. All on-demand compute prices for the region are extracted in a single pass and cached in SQLite for 24 hours. Concurrent requests for the same region share a single download.
|
|
190
274
|
|
|
191
|
-
2. **Live JSON API** (secondary)
|
|
275
|
+
2. **Live JSON API** (secondary). For RDS (~24 MB), S3, ELB, and VPC, the server fetches regional JSON from the [AWS Price List Bulk API](https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json). These files are small enough to parse directly.
|
|
192
276
|
|
|
193
|
-
3. **Fallback tables + interpolation
|
|
277
|
+
3. **Fallback tables + interpolation**. If live fetching fails (network issues, timeouts), the server falls back to built-in pricing tables covering 85+ EC2 and 29 RDS instance types. A size-interpolation algorithm estimates prices for unlisted sizes within known families by following AWS's predictable doubling pattern (e.g., `large` to `xlarge` doubles the price).
|
|
194
278
|
|
|
195
279
|
### Azure
|
|
196
280
|
|
|
197
|
-
1. **Live REST API** (primary)
|
|
281
|
+
1. **Live REST API** (primary). Queries the [Azure Retail Prices API](https://prices.azure.com/api/retail/prices) with OData filters for exact SKU matching (`armSkuName`). Fast, free, unauthenticated. Returns precise per-SKU pricing. Results are paginated and fully consumed.
|
|
198
282
|
|
|
199
|
-
2. **Fallback tables + interpolation
|
|
283
|
+
2. **Fallback tables + interpolation**. If the API is unreachable, falls back to built-in tables covering 40+ VM sizes and 14 database tiers. A vCPU-proportional interpolation algorithm estimates prices for unlisted sizes.
|
|
200
284
|
|
|
201
285
|
### GCP
|
|
202
286
|
|
|
203
|
-
1. **
|
|
287
|
+
1. **Live Cloud Billing Catalog API** (primary). Queries the GCP Cloud Billing Catalog API (`cloudbilling.googleapis.com`) using unauthenticated public endpoints. Results are cached for 24 hours.
|
|
288
|
+
|
|
289
|
+
2. **Bundled pricing data** (fallback). If the live API is unreachable, falls back to curated pricing data in `data/gcp-pricing/` that ships with the package. Covers Compute Engine machine types, Cloud SQL tiers, Cloud Storage classes, and Persistent Disk types across all major regions.
|
|
204
290
|
|
|
205
|
-
|
|
291
|
+
3. **Infrastructure services**. Load balancer, Cloud NAT, and GKE pricing use fixed public rates.
|
|
206
292
|
|
|
207
293
|
### Pricing Source Transparency
|
|
208
294
|
|
|
209
295
|
Every price returned includes a `pricing_source` attribute indicating its origin:
|
|
210
|
-
- `"live"
|
|
211
|
-
- `"fallback"
|
|
212
|
-
- `"bundled"
|
|
296
|
+
- `"live"`: fetched from a public API in real time
|
|
297
|
+
- `"fallback"`: from built-in tables (approximate, but reasonable for estimates)
|
|
298
|
+
- `"bundled"`: from bundled data files shipped with the package
|
|
213
299
|
|
|
214
300
|
All pricing data is cached in a local SQLite database (`~/.cloudcost/cache.db`) with a 24-hour TTL to minimize redundant API calls.
|
|
215
301
|
|
|
@@ -288,6 +374,12 @@ All configuration is optional. The server works out of the box with sensible def
|
|
|
288
374
|
| `CLOUDCOST_CACHE_PATH` | `~/.cloudcost/cache.db` | SQLite cache file location |
|
|
289
375
|
| `CLOUDCOST_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
|
290
376
|
| `CLOUDCOST_MONTHLY_HOURS` | `730` | Hours per month for cost calculations |
|
|
377
|
+
| `CLOUDCOST_INCLUDE_DATA_TRANSFER` | `false` | Include estimated data transfer costs in reports |
|
|
378
|
+
| `CLOUDCOST_PRICING_MODEL` | `on_demand` | Default pricing model: `on_demand`, `spot`, or `reserved` |
|
|
379
|
+
| `CLOUDCOST_RESOLVE_MODULES` | `true` | Expand referenced Terraform modules during parsing |
|
|
380
|
+
| `CLOUDCOST_BUDGET_MONTHLY` | | Monthly budget cap in USD. Triggers a warning when exceeded |
|
|
381
|
+
| `CLOUDCOST_BUDGET_PER_RESOURCE` | | Per-resource monthly budget cap in USD |
|
|
382
|
+
| `CLOUDCOST_BUDGET_WARN_PCT` | `80` | Percentage of budget at which a warning is surfaced (default: 80%) |
|
|
291
383
|
|
|
292
384
|
### Config File
|
|
293
385
|
|
|
@@ -351,11 +443,11 @@ Configuration priority: environment variables > config file > built-in defaults.
|
|
|
351
443
|
|
|
352
444
|
### Key Design Decisions
|
|
353
445
|
|
|
354
|
-
- **Zero API keys
|
|
355
|
-
- **SQLite cache
|
|
356
|
-
- **Streaming for large files
|
|
357
|
-
- **Graceful degradation
|
|
358
|
-
- **ESM-only
|
|
446
|
+
- **Zero API keys.** All pricing comes from public endpoints. AWS uses the unauthenticated Bulk Pricing files. Azure uses the free Retail Prices REST API. GCP queries the Cloud Billing Catalog API with bundled fallback.
|
|
447
|
+
- **SQLite cache.** A single `better-sqlite3` database caches all pricing lookups with configurable TTL. Shared across all tools per server lifetime.
|
|
448
|
+
- **Streaming for large files.** AWS EC2 pricing data (~267 MB CSV) is streamed line-by-line rather than loaded into memory. Prices for a region are extracted in one pass and cached.
|
|
449
|
+
- **Graceful degradation.** If any live pricing source is unavailable, the server falls back to built-in tables with size-interpolation. Every response includes the pricing source so the consumer knows the confidence level.
|
|
450
|
+
- **ESM-only.** Requires Node 20+. All internal imports use `.js` extensions.
|
|
359
451
|
|
|
360
452
|
---
|
|
361
453
|
|
|
@@ -363,11 +455,19 @@ Configuration priority: environment variables > config file > built-in defaults.
|
|
|
363
455
|
|
|
364
456
|
| Category | AWS | Azure | GCP |
|
|
365
457
|
|----------|-----|-------|-----|
|
|
366
|
-
| **Compute** | `aws_instance
|
|
458
|
+
| **Compute** | `aws_instance` | `azurerm_virtual_machine`, `azurerm_linux_virtual_machine` | `google_compute_instance` |
|
|
367
459
|
| **Database** | `aws_db_instance`, `aws_rds_cluster` | `azurerm_postgresql_flexible_server`, `azurerm_mysql_flexible_server` | `google_sql_database_instance` |
|
|
368
460
|
| **Storage** | `aws_ebs_volume`, `aws_s3_bucket` | `azurerm_managed_disk`, `azurerm_storage_account` | `google_compute_disk`, `google_storage_bucket` |
|
|
369
461
|
| **Network** | `aws_lb`, `aws_nat_gateway` | `azurerm_lb`, `azurerm_nat_gateway` | `google_compute_forwarding_rule` |
|
|
370
462
|
| **Kubernetes** | `aws_eks_cluster` | `azurerm_kubernetes_cluster` | `google_container_cluster` |
|
|
463
|
+
| **Container Registries** | `aws_ecr_repository` | `azurerm_container_registry` | `google_artifact_registry_repository` |
|
|
464
|
+
| **Secrets Management** | `aws_secretsmanager_secret` | `azurerm_key_vault` | `google_secret_manager_secret` |
|
|
465
|
+
| **DNS** | `aws_route53_zone` | `azurerm_dns_zone` | `google_dns_managed_zone` |
|
|
466
|
+
| **API Gateway** | `aws_api_gateway_rest_api`, `aws_apigatewayv2_api` | `azurerm_api_management` | `google_api_gateway_api` |
|
|
467
|
+
| **WAF** | `aws_wafv2_web_acl` | `azurerm_web_application_firewall_policy` | |
|
|
468
|
+
| **OpenSearch** | `aws_opensearch_domain` | | |
|
|
469
|
+
| **Messaging** | `aws_sns_topic`, `aws_mq_broker` | `azurerm_servicebus_namespace`, `azurerm_eventhub_namespace` | `google_pubsub_topic` |
|
|
470
|
+
| **ML/AI** | `aws_sagemaker_endpoint`, `aws_sagemaker_notebook_instance` | | `google_vertex_ai_endpoint` |
|
|
371
471
|
|
|
372
472
|
Instance type mapping covers 70+ AWS instance types (including Graviton/ARM families: m6g, m7g, c6g, c7g, r6g, r7g, t4g), 40+ Azure VM sizes, and 20+ GCP machine types with full bidirectional cross-provider mapping.
|
|
373
473
|
|
|
@@ -375,10 +475,8 @@ Instance type mapping covers 70+ AWS instance types (including Graviton/ARM fami
|
|
|
375
475
|
|
|
376
476
|
## Limitations
|
|
377
477
|
|
|
378
|
-
- **
|
|
379
|
-
- **
|
|
380
|
-
- **No Terraform module expansion**. Only direct resource blocks in the provided files are parsed. Resources defined inside referenced modules (`source = "..."`) are not resolved.
|
|
381
|
-
- **GCP pricing is bundled**, not live. Prices may lag behind actual rates. AWS and Azure pricing is fetched in real time.
|
|
478
|
+
- **On-demand pricing only** by default. Prices reflect pay-as-you-go rates. The `optimize_cost` tool will recommend reserved instances and savings plans, but base estimates use on-demand. Pass `pricing_model: "spot"` in `what_if` scenarios to model spot/preemptible pricing.
|
|
479
|
+
- **GCP live pricing** is fetched from the Cloud Billing Catalog API with automatic fallback to bundled data when the API is unreachable. Bundled prices may lag slightly behind actual rates.
|
|
382
480
|
- **First request latency**. The initial EC2 pricing lookup for a new AWS region may take 30-120 seconds as the CSV file is streamed. Subsequent lookups for the same region are instant (cached for 24 hours).
|
|
383
481
|
- **Specialty instance types**. GPU instances (p4d, g5, etc.), high-memory (x2idn), and bare-metal types may fall back to interpolated pricing if not in the built-in tables and live fetch fails.
|
|
384
482
|
|
|
@@ -386,13 +484,49 @@ Instance type mapping covers 70+ AWS instance types (including Graviton/ARM fami
|
|
|
386
484
|
|
|
387
485
|
## Troubleshooting
|
|
388
486
|
|
|
389
|
-
**$0 cost estimates
|
|
487
|
+
**$0 cost estimates.** The instance type string in your Terraform code probably doesn't match any known pricing data. Check that you're using a real instance type (e.g., `t3.xlarge`) rather than a variable reference that wasn't resolved. Pass your `terraform.tfvars` content via the `tfvars` parameter to resolve variables.
|
|
390
488
|
|
|
391
|
-
**Slow first request
|
|
489
|
+
**Slow first request.** The first EC2 pricing lookup for a new region streams the full AWS pricing CSV (~267 MB). One-time cost per region; subsequent lookups hit the local SQLite cache. Set `CLOUDCOST_LOG_LEVEL=debug` to see progress.
|
|
392
490
|
|
|
393
|
-
**Cache issues
|
|
491
|
+
**Cache issues.** Delete `~/.cloudcost/cache.db` to clear all cached pricing data. The cache rebuilds automatically on the next request.
|
|
492
|
+
|
|
493
|
+
**Node version.** Requires Node.js 20+. Uses ESM modules, Web Streams API (`TextDecoderStream`), and `AbortSignal.timeout()`.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## GitHub Actions
|
|
498
|
+
|
|
499
|
+
A reusable composite action is included at `.github/actions/cost-estimate/`. It detects changed `.tf` files, runs a cost comparison, and posts the result as a PR comment.
|
|
500
|
+
|
|
501
|
+
```yaml
|
|
502
|
+
# .github/workflows/cost-estimate.yml
|
|
503
|
+
name: Terraform Cost Estimate
|
|
504
|
+
|
|
505
|
+
on:
|
|
506
|
+
pull_request:
|
|
507
|
+
types: [opened, synchronize]
|
|
508
|
+
|
|
509
|
+
jobs:
|
|
510
|
+
cost-estimate:
|
|
511
|
+
runs-on: ubuntu-latest
|
|
512
|
+
permissions:
|
|
513
|
+
contents: read
|
|
514
|
+
pull-requests: write
|
|
515
|
+
steps:
|
|
516
|
+
- uses: actions/checkout@v4
|
|
517
|
+
with:
|
|
518
|
+
fetch-depth: 0
|
|
519
|
+
|
|
520
|
+
- uses: ./.github/actions/cost-estimate
|
|
521
|
+
with:
|
|
522
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
523
|
+
# terraform_dir: "./terraform"
|
|
524
|
+
# providers: "aws,azure,gcp"
|
|
525
|
+
# format: "markdown"
|
|
526
|
+
# currency: "USD"
|
|
527
|
+
```
|
|
394
528
|
|
|
395
|
-
|
|
529
|
+
The action auto-detects the directory containing changed `.tf` files and skips gracefully when no Terraform changes are present in the PR.
|
|
396
530
|
|
|
397
531
|
---
|
|
398
532
|
|
|
@@ -414,17 +548,32 @@ src/
|
|
|
414
548
|
├── server.ts # MCP server setup, tool registration
|
|
415
549
|
├── config.ts # Config loader (defaults → file → env vars)
|
|
416
550
|
├── logger.ts # Structured logger
|
|
417
|
-
├──
|
|
418
|
-
├──
|
|
551
|
+
├── currency.ts # Multi-currency conversion and formatting
|
|
552
|
+
├── tools/
|
|
553
|
+
│ ├── ... # MCP tool handlers + Zod schemas
|
|
554
|
+
│ └── what-if.ts # Hypothetical scenario modeling
|
|
555
|
+
├── parsers/
|
|
556
|
+
│ ├── ... # HCL parsing, variable resolution
|
|
557
|
+
│ ├── module-resolver.ts # Terraform module expansion
|
|
558
|
+
│ └── dependency-graph.ts # Resource dependency graph builder
|
|
419
559
|
├── pricing/
|
|
420
560
|
│ ├── pricing-engine.ts # Router: dispatches to provider adapters
|
|
421
561
|
│ ├── cache.ts # SQLite-backed pricing cache
|
|
422
562
|
│ ├── aws/ # Bulk CSV streaming + JSON + fallback
|
|
423
563
|
│ ├── azure/ # Retail Prices REST API + fallback
|
|
424
|
-
│ └── gcp/
|
|
425
|
-
├──
|
|
564
|
+
│ └── gcp/
|
|
565
|
+
│ ├── bundled-loader.ts # Static bundled pricing fallback
|
|
566
|
+
│ └── cloud-billing-client.ts # Live GCP Cloud Billing Catalog API
|
|
567
|
+
├── calculator/
|
|
568
|
+
│ ├── ... # Cost calculations per resource type
|
|
569
|
+
│ ├── projection.ts # Multi-horizon cost projections
|
|
570
|
+
│ ├── container-registry.ts
|
|
571
|
+
│ ├── secrets.ts
|
|
572
|
+
│ └── dns.ts
|
|
426
573
|
├── mapping/ # Cross-provider resource/instance mapping
|
|
427
|
-
├── reporting/
|
|
574
|
+
├── reporting/
|
|
575
|
+
│ ├── ... # Markdown, JSON, CSV formatters
|
|
576
|
+
│ └── focus-report.ts # FOCUS-compliant export format
|
|
428
577
|
└── types/ # Shared TypeScript interfaces
|
|
429
578
|
|
|
430
579
|
data/
|
|
@@ -438,4 +587,4 @@ data/
|
|
|
438
587
|
|
|
439
588
|
## License
|
|
440
589
|
|
|
441
|
-
MIT
|
|
590
|
+
MIT. See [LICENSE](LICENSE) for details.
|
|
@@ -1,72 +1,107 @@
|
|
|
1
1
|
{
|
|
2
2
|
"us-central1": {
|
|
3
|
-
"db-custom-1-3840": 0.
|
|
4
|
-
"db-custom-2-7680": 0.
|
|
5
|
-
"db-custom-4-15360": 0.
|
|
3
|
+
"db-custom-1-3840": 0.0515,
|
|
4
|
+
"db-custom-2-7680": 0.1030,
|
|
5
|
+
"db-custom-4-15360": 0.2060,
|
|
6
6
|
"storage_per_gb": 0.170,
|
|
7
7
|
"ha_multiplier": 2.0
|
|
8
8
|
},
|
|
9
9
|
"us-east1": {
|
|
10
|
-
"db-custom-1-3840": 0.
|
|
11
|
-
"db-custom-2-7680": 0.
|
|
12
|
-
"db-custom-4-15360": 0.
|
|
10
|
+
"db-custom-1-3840": 0.0515,
|
|
11
|
+
"db-custom-2-7680": 0.1030,
|
|
12
|
+
"db-custom-4-15360": 0.2060,
|
|
13
13
|
"storage_per_gb": 0.170,
|
|
14
14
|
"ha_multiplier": 2.0
|
|
15
15
|
},
|
|
16
|
-
"
|
|
17
|
-
"db-custom-1-3840": 0.
|
|
18
|
-
"db-custom-2-7680": 0.
|
|
19
|
-
"db-custom-4-15360": 0.
|
|
20
|
-
"storage_per_gb": 0.
|
|
16
|
+
"us-east4": {
|
|
17
|
+
"db-custom-1-3840": 0.0580,
|
|
18
|
+
"db-custom-2-7680": 0.1161,
|
|
19
|
+
"db-custom-4-15360": 0.2322,
|
|
20
|
+
"storage_per_gb": 0.192,
|
|
21
21
|
"ha_multiplier": 2.0
|
|
22
22
|
},
|
|
23
23
|
"us-west1": {
|
|
24
|
-
"db-custom-1-3840": 0.
|
|
25
|
-
"db-custom-2-7680": 0.
|
|
26
|
-
"db-custom-4-15360": 0.
|
|
24
|
+
"db-custom-1-3840": 0.0515,
|
|
25
|
+
"db-custom-2-7680": 0.1030,
|
|
26
|
+
"db-custom-4-15360": 0.2060,
|
|
27
27
|
"storage_per_gb": 0.170,
|
|
28
28
|
"ha_multiplier": 2.0
|
|
29
29
|
},
|
|
30
|
-
"
|
|
31
|
-
"db-custom-1-3840": 0.
|
|
32
|
-
"db-custom-2-7680": 0.
|
|
33
|
-
"db-custom-4-15360": 0.
|
|
34
|
-
"storage_per_gb": 0.196,
|
|
35
|
-
"ha_multiplier": 2.0
|
|
36
|
-
},
|
|
37
|
-
"asia-south1": {
|
|
38
|
-
"db-custom-1-3840": 0.0525,
|
|
39
|
-
"db-custom-2-7680": 0.1050,
|
|
40
|
-
"db-custom-4-15360": 0.2100,
|
|
30
|
+
"us-west4": {
|
|
31
|
+
"db-custom-1-3840": 0.0541,
|
|
32
|
+
"db-custom-2-7680": 0.1082,
|
|
33
|
+
"db-custom-4-15360": 0.2163,
|
|
41
34
|
"storage_per_gb": 0.179,
|
|
42
35
|
"ha_multiplier": 2.0
|
|
43
36
|
},
|
|
44
|
-
"
|
|
45
|
-
"db-custom-1-3840": 0.
|
|
46
|
-
"db-custom-2-7680": 0.
|
|
47
|
-
"db-custom-4-15360": 0.
|
|
48
|
-
"storage_per_gb": 0.
|
|
37
|
+
"europe-west1": {
|
|
38
|
+
"db-custom-1-3840": 0.0567,
|
|
39
|
+
"db-custom-2-7680": 0.1133,
|
|
40
|
+
"db-custom-4-15360": 0.2266,
|
|
41
|
+
"storage_per_gb": 0.187,
|
|
49
42
|
"ha_multiplier": 2.0
|
|
50
43
|
},
|
|
51
44
|
"europe-west2": {
|
|
52
|
-
"db-custom-1-3840": 0.
|
|
53
|
-
"db-custom-2-7680": 0.
|
|
54
|
-
"db-custom-4-15360": 0.
|
|
45
|
+
"db-custom-1-3840": 0.0567,
|
|
46
|
+
"db-custom-2-7680": 0.1133,
|
|
47
|
+
"db-custom-4-15360": 0.2266,
|
|
55
48
|
"storage_per_gb": 0.187,
|
|
56
49
|
"ha_multiplier": 2.0
|
|
57
50
|
},
|
|
51
|
+
"europe-west3": {
|
|
52
|
+
"db-custom-1-3840": 0.0577,
|
|
53
|
+
"db-custom-2-7680": 0.1154,
|
|
54
|
+
"db-custom-4-15360": 0.2307,
|
|
55
|
+
"storage_per_gb": 0.190,
|
|
56
|
+
"ha_multiplier": 2.0
|
|
57
|
+
},
|
|
58
58
|
"europe-west4": {
|
|
59
|
-
"db-custom-1-3840": 0.
|
|
60
|
-
"db-custom-2-7680": 0.
|
|
61
|
-
"db-custom-4-15360": 0.
|
|
59
|
+
"db-custom-1-3840": 0.0567,
|
|
60
|
+
"db-custom-2-7680": 0.1133,
|
|
61
|
+
"db-custom-4-15360": 0.2266,
|
|
62
62
|
"storage_per_gb": 0.187,
|
|
63
63
|
"ha_multiplier": 2.0
|
|
64
64
|
},
|
|
65
|
+
"europe-north1": {
|
|
66
|
+
"db-custom-1-3840": 0.0556,
|
|
67
|
+
"db-custom-2-7680": 0.1112,
|
|
68
|
+
"db-custom-4-15360": 0.2225,
|
|
69
|
+
"storage_per_gb": 0.184,
|
|
70
|
+
"ha_multiplier": 2.0
|
|
71
|
+
},
|
|
72
|
+
"asia-northeast1": {
|
|
73
|
+
"db-custom-1-3840": 0.0593,
|
|
74
|
+
"db-custom-2-7680": 0.1185,
|
|
75
|
+
"db-custom-4-15360": 0.2370,
|
|
76
|
+
"storage_per_gb": 0.196,
|
|
77
|
+
"ha_multiplier": 2.0
|
|
78
|
+
},
|
|
79
|
+
"asia-south1": {
|
|
80
|
+
"db-custom-1-3840": 0.0541,
|
|
81
|
+
"db-custom-2-7680": 0.1082,
|
|
82
|
+
"db-custom-4-15360": 0.2163,
|
|
83
|
+
"storage_per_gb": 0.179,
|
|
84
|
+
"ha_multiplier": 2.0
|
|
85
|
+
},
|
|
86
|
+
"australia-southeast1": {
|
|
87
|
+
"db-custom-1-3840": 0.0608,
|
|
88
|
+
"db-custom-2-7680": 0.1216,
|
|
89
|
+
"db-custom-4-15360": 0.2431,
|
|
90
|
+
"storage_per_gb": 0.201,
|
|
91
|
+
"ha_multiplier": 2.0
|
|
92
|
+
},
|
|
65
93
|
"northamerica-northeast1": {
|
|
66
|
-
"db-custom-1-3840": 0.
|
|
67
|
-
"db-custom-2-7680": 0.
|
|
68
|
-
"db-custom-4-15360": 0.
|
|
94
|
+
"db-custom-1-3840": 0.0541,
|
|
95
|
+
"db-custom-2-7680": 0.1082,
|
|
96
|
+
"db-custom-4-15360": 0.2163,
|
|
69
97
|
"storage_per_gb": 0.179,
|
|
70
98
|
"ha_multiplier": 2.0
|
|
99
|
+
},
|
|
100
|
+
"southamerica-east1": {
|
|
101
|
+
"db-custom-1-3840": 0.0659,
|
|
102
|
+
"db-custom-2-7680": 0.1318,
|
|
103
|
+
"db-custom-4-15360": 0.2637,
|
|
104
|
+
"storage_per_gb": 0.218,
|
|
105
|
+
"ha_multiplier": 2.0
|
|
71
106
|
}
|
|
72
107
|
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"us-central1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
3
3
|
"us-east1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
4
|
+
"us-east4": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
5
|
+
"us-west1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
6
|
+
"us-west4": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
4
7
|
"europe-west1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
8
|
+
"europe-west2": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
9
|
+
"europe-west3": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
10
|
+
"europe-west4": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
11
|
+
"europe-north1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
5
12
|
"asia-southeast1": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
6
|
-
"us-west1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
7
13
|
"asia-northeast1": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
8
|
-
"asia-south1": { "STANDARD": 0.
|
|
9
|
-
"australia-southeast1": { "STANDARD": 0.
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"northamerica-northeast1": { "STANDARD": 0.021, "NEARLINE": 0.011, "COLDLINE": 0.005, "ARCHIVE": 0.0013 }
|
|
14
|
+
"asia-south1": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
15
|
+
"australia-southeast1": { "STANDARD": 0.023, "NEARLINE": 0.013, "COLDLINE": 0.006, "ARCHIVE": 0.0015 },
|
|
16
|
+
"northamerica-northeast1": { "STANDARD": 0.020, "NEARLINE": 0.010, "COLDLINE": 0.004, "ARCHIVE": 0.0012 },
|
|
17
|
+
"southamerica-east1": { "STANDARD": 0.035, "NEARLINE": 0.020, "COLDLINE": 0.007, "ARCHIVE": 0.0025 }
|
|
13
18
|
}
|