Repository navigation
fix(billing-cost-management-mcp-server): return null for an estimate's IssuedDate and document filter limits - #4987
Open
finklen-amazon wants to merge 9 commits into
Open
finklen-amazon wants to merge 9 commits into
finklen-amazon wants to merge 9 commits into
Conversation
…age, coerce boolean filters, fold summaries group_by
- list_recommendation_summaries now sends metrics=['SavingsPercentage'].
Without it the service returns the placeholder "Percentage not
requested." in metrics.savingsPercentage, which the tool passed through
as a metric. A percentage value ('12%', '>=80%', '<=2%') is returned as
metrics.savings_percentage; any other text the service puts in that
field (before-discounts mode, unsupported filter, not calculable) is
returned as metrics.savings_percentage_unavailable_reason. A metrics
block without a string value gives no metrics key.
- restartNeeded / rollbackPossible filters given as "true"/"false"
strings are coerced to booleans instead of failing botocore parameter
validation.
- Summaries group_by fixed dimensions match case- and
underscore-insensitively (resource_type -> ResourceType), like filter
keys. The missing-group_by error lists the same values as the
invalid-group_by error, including TagKey:<tag key>. The unreachable
'RESOURCE_TYPE' fallback is removed.
- The description documents the savings percentage and its limits, the
resourceIds / resourceArns / recommendationIds filters (list only;
summaries reject them), that there is no
per-service resource type filter, and that summary fields are the same
on every page, including continuation calls (it said they were not
repeated).
No tool parameter is added, renamed, retyped or given a new default.
BREAKING CHANGE: cost-optimization list_recommendation_summaries no
longer returns the service's explanation text in
metrics.savings_percentage. When no percentage is computed,
metrics.savings_percentage is absent and the text is in
metrics.savings_percentage_unavailable_reason. Before this change the
field always held the "Percentage not requested." placeholder.
… excludes credits and refunds The service computes metrics.savingsPercentage against the last 30 days' net amortized cost with the Credit and Refund record types filtered out. Say so in the cost-optimization description and the CHANGELOG entry, so a caller comparing it to Cost Explorer's net amortized cost with no record-type filter knows why the figures differ. Also say that total_recommendation_count is not one of the summary fields repeated on every page, and drop the CHANGELOG clause about documenting the ID filters, which main already covers.
… case-insensitively only Fold only letter case in list_recommendation_summaries group_by, not underscores, so the legacy upper-snake spelling RESOURCE_TYPE (and resource_type) is rejected locally as an invalid dimension instead of being sent as ResourceType. resourcetype and ACCOUNTID still resolve. The description, the CHANGELOG entry and the tests say the same.
…len-amazon/mcp into fix/bcm-coh-summary-filters
# Conflicts: # src/billing-cost-management-mcp-server/awslabs/billing_cost_management_mcp_server/tools/cost_optimization_hub_helpers.py # src/billing-cost-management-mcp-server/awslabs/billing_cost_management_mcp_server/tools/cost_optimization_hub_tools.py # src/billing-cost-management-mcp-server/tests/tools/test_cost_optimization_hub_tools.py
…s IssuedDate and document filter limits invoicing: an estimated invoice's IssuedDate (the epoch, meaning unset) is returned as null instead of 1970-01-01, and every summary carries is_estimate (InvoiceId prefixed "Estimate-"). The description now uses both instead of the 1970 date. cost-explorer: getCostAndUsageWithResources responses carry the user: tag-key hint, since a user:-prefixed key matches nothing there too. Documented: MatchOptions must include EQUALS (or ABSENT); at most 6,000 filter values across all leaves; PAYER_ACCOUNT; an empty tag key with an empty Values list matches untagged costs; the forecasts accept either tag-key form. Description fixes, each checked against the service: - cost-comparison: at most 200 filter values in total - session-sql: drop the reference to a cost_explorer_sql tool that does not exist - compute-optimizer: RDS idle is separate from the instance finding; where savingsEstimationMode.source is - aws-pricing: RDS filters (and the UnusedBox twin product), Windows licenseModel - describe-cost-category-definition: split charge rules apply only on the console's cost category details page - get-billing-view: a cost-category value of "" matches uncategorized costs - storage-lens: report_date is a string in CSV and Parquet exports
finklen-amazon
requested review from
a team,
Comusus,
Dinkie,
Rahul-1404,
anniewn,
bhatia-di,
callnmm,
chittev,
johnwangwyx,
junaidgirkar,
mattkelsey,
shsrams,
somsubhro,
wangyuhere and
yasmeenh11
as code owners
November 2, 2026 01:26
# Conflicts: # src/billing-cost-management-mcp-server/awslabs/billing_cost_management_mcp_server/tools/aws_pricing_tools.py
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4987 +/- ##
==========================================
- Coverage 93.79% 93.79% -0.01%
==========================================
Files 1080 1080
Lines 94701 94725 +24
Branches 15434 15439 +5
==========================================
+ Hits 88828 88849 +21
- Misses 3500 3501 +1
- Partials 2373 2375 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
Summary
Stacked on #4906: until it merges, this PR's diff also shows #4906's commits. Only the last commit,
fix(billing-cost-management-mcp-server): return null for an estimate's IssuedDate and document filter limits, is new here.Changes
invoicingreturnsIssuedDate: nullfor an estimated invoice instead of1970-01-01T00:00:00, and every summary carriesis_estimate.An estimate (returned only with
receiver_role) has anIssuedDateof the Unix epoch, meaning unset. The tool turned that into1970-01-01T00:00:00, and the description had to warn callers never to report it. The estimate'sDueDateis a real date and is kept.IssuedDateequal to the epoch (as a datetime in any time zone, or as epoch seconds) is nownull.is_estimateistruewhenInvoiceIdstarts withEstimate-, the only field that tells an estimate from an issued invoice, andfalseotherwise.cost-explorerattaches theuser:tag-key hint togetCostAndUsageWithResourcestoo. Auser:-prefixed tag key matches nothing there, with no error, as ingetCostAndUsage. The forecasts accept either form, so they still get no hint.Description changes, each checked against the service:
MatchOptionsis passed it must includeEQUALS(orABSENT):["CASE_SENSITIVE"]alone is rejected, andABSENTtakes no case option.Not.getCostAndUsageonly:{"Tags": {"Key": "", "Values": []}}matches costs that carry no activated cost allocation tag, as doesABSENTwith noKey. Other forms of an empty key are rejected, andgetDimensionValuesandgetCostAndUsageWithResourcesreject an empty key.getCostAndUsageWithResourcesand says the forecasts accept either tag-key form.PAYER_ACCOUNT(the management account's ID). The service enables it per account, so the entry says to useLINKED_ACCOUNTif it is rejected.cost_explorer_sqltool that does not exist, and says how to recognize an offloaded result (data.data_stored,data.table_name).idleandinstance_findingare computed separately, so a DB instance can be Optimized and idle.idleis null for Aurora cluster recommendations.effective_recommendation_preferences.savingsEstimationMode.sourcenames the source of the savings figures (every type except idle).licenseModel:No License requiredis the standard Windows On-Demand price, and the other values are separate, cheaper products.databaseEngineanddeploymentOption. Even then anUnusedBoxtwin at the same price (with no hardware attributes) can match, and Aurora adds a higher-pricedInstanceUsageIOOptimizedproduct. SQL Server and Oracle also needlicenseModelanddatabaseEdition;deploymentModelCustomrows are RDS Custom.""in a view filter matches the costs no rule of that category assigns a value to.report_dateis a string in CSV and Parquet exports.User experience
Before, an estimate in
list_invoice_summarieswithreceiver_role:After:
Issued invoices keep their
IssuedDateand get"is_estimate": false.Testing
All commands run from
src/billing-cost-management-mcp-server.uv run --frozen pytest: 4286 passed.ruff format,ruff checkandpyrightare clean.IssuedDate/is_estimatecases (epoch as UTC datetime, int, float and a non-UTC aware datetime; issued invoice; prefix only at the start), thegetCostAndUsageWithResourceshint, the per-accountPAYER_ACCOUNTcontract, and the description contracts for each tool above. The other changed tests are regression guards that already pass there (for example, the forecasts still get no hint, and the existing epoch-to-ISO conversions are unchanged).["CASE_SENSITIVE"]alone vs["EQUALS", "CASE_SENSITIVE"]; 6,000 vs 6,001 values split over two leaves; untagged plusNotuntagged equals the unfiltered total; auser:key vs the bare key ingetCostAndUsageWithResources; 200 vs 201 values in both comparison operations; a billing view with cost-category values["", "<value>"]equals the uncategorized plus that value's cost.getCostAndUsageWithResourceshint and both invoice checks; the AWS-only behavior checks pass on both, since the request sent is the same.getCostAndUsage,ABSENTrejects a case option,PAYER_ACCOUNTis listed in the API reference,idleis null rather than absent for Aurora clusters, and the RDS pricing products vary by engine and deployment option.Checklist
If your change doesn't seem to apply, please leave them unchecked.
Is this a breaking change? (Y/N) N. An estimate's
IssuedDatewas documented as the epoch meaning unset; it is nownull, andis_estimateis a new field. No parameter or tool is renamed or removed.RFC issue number:
Checklist:
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.