Skip to content

Commit 46c1d2f

Browse files
fix(billing-cost-management-mcp-server): describe efficiency Monthly points as month-end snapshots (#4877)
* fix(billing-cost-management-mcp-server): describe efficiency Monthly points as month-end snapshots The cost-optimization description sent trend and month-over-month questions to list_efficiency_metrics, which defaults to Monthly granularity. A Monthly efficiency point is not a monthly average or total: it is the Daily snapshot for the month's last day (savings from the last day that has data, spend for the 30 days ending on the month's last day). A change on that one day therefore moved the whole month's value and read as a monthly trend. The description and the granularity docs now say what a Monthly point is, send trend questions to Daily, note that only completed months are returned, and state that each point is a one-day snapshot whose spend covers the 30 days ending that day. * chore: drop CHANGELOG entry (non-breaking change) * fix(billing-cost-management-mcp-server): ask only for completed efficiency months "Only completed months are returned" is not guaranteed: the request validator allows one day of tolerance at month-end. Say instead to ask only for completed months (end_date no later than the current month, since end is exclusive), and that a current-month point would be partial. Describe spend as the trailing 30 days rather than pinning the window's last day, which public material and the service code state differently.
1 parent 6fff00c commit 46c1d2f

3 files changed

Lines changed: 58 additions & 6 deletions

File tree

‎src/billing-cost-management-mcp-server/awslabs/billing_cost_management_mcp_server/tools/cost_optimization_hub_helpers.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,10 @@ async def list_efficiency_metrics(
619619
"""List cost efficiency metrics from Cost Optimization Hub.
620620
621621
Returns time-series efficiency data (efficiency score, estimated savings, and
622-
spend) aggregated over the requested time period and optionally grouped by
623-
account ID or Region.
622+
spend), optionally grouped by account ID or Region. Each point is a one-day
623+
snapshot (estimated savings of the recommendations open that day, against the
624+
trailing 30 days of spend); a Monthly point is the snapshot for the last day
625+
of the month that has data, with the trailing 30 days of spend at month-end.
624626
625627
Fetches every page, or stops before exceeding ``max_items``, and returns the combined
626628
groups with a ``pagination`` block. ``orderBy`` is sent on every page. In ``performance``

‎src/billing-cost-management-mcp-server/awslabs/billing_cost_management_mcp_server/tools/cost_optimization_hub_tools.py‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,10 @@ def _validate_order_by(
397397
3. get_recommendation: Get detailed information about a specific recommendation
398398
4. list_efficiency_metrics: Cost efficiency score, estimated savings, and spend as
399399
a time series (optionally grouped by AccountId or Region). Use for questions
400-
about the cost-efficiency score, its trend over time, month-over-month change,
401-
cross-region/cross-account comparison, and top/worst performers.
400+
about the cost-efficiency score, how it changed over time (use 'Daily' for
401+
that), cross-region/cross-account comparison, and top/worst performers. Each
402+
point is a one-day snapshot, not a period total: the estimated savings of the
403+
recommendations open on that day, against the trailing 30 days of spend.
402404
5. list_enrollment_statuses: Cost Optimization Hub enrollment status (Active/Inactive)
403405
of the calling account. Optional 'account_id' returns the status of that account instead.
404406
An account that has never enrolled has no enrollment record; it is reported as
@@ -431,7 +433,15 @@ def _validate_order_by(
431433
- Service only available in us-east-1 region
432434
433435
list_efficiency_metrics parameters:
434-
- 'granularity': 'Daily' or 'Monthly' (defaults to 'Monthly' when omitted)
436+
- 'granularity': 'Daily' or 'Monthly' (defaults to 'Monthly' when omitted).
437+
A Monthly point ('YYYY-MM') is not a monthly average or total: it is the
438+
snapshot for the last day of the month that has data, with the trailing 30
439+
days of spend at month-end, so a change on that one day moves the month's
440+
value. Ask only for completed months (end_date no later than the current
441+
month, since end is exclusive); a current-month point would be partial. For a
442+
trend or a change over time, use 'Daily' and read the daily series rather than
443+
comparing Monthly values. When reporting a Monthly value, say it is the
444+
month-end snapshot.
435445
- 'start_date' / 'end_date': window bounds as 'YYYY-MM-DD' (daily) or 'YYYY-MM'
436446
(monthly); end is exclusive. Both default to a ~90-day lookback when omitted.
437447
The API only serves data whose start is within the most recent 90 days (Daily)
@@ -519,7 +529,9 @@ async def cost_optimization_hub(
519529
Applies to list_recommendations, list_recommendation_summaries, and
520530
list_efficiency_metrics.
521531
granularity: Time granularity for list_efficiency_metrics ('Daily' or
522-
'Monthly'). Defaults to 'Monthly' when omitted.
532+
'Monthly'). Defaults to 'Monthly' when omitted. A Monthly point is the
533+
month-end snapshot (the last day of the month that has data), not a
534+
monthly average; use 'Daily' for trends.
523535
start_date: Inclusive window start for list_efficiency_metrics
524536
('YYYY-MM-DD' or 'YYYY-MM'). Defaults to a ~90-day lookback when omitted.
525537
end_date: Exclusive window end for list_efficiency_metrics ('YYYY-MM-DD'

‎src/billing-cost-management-mcp-server/tests/tools/test_cost_optimization_hub_tools.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,3 +1858,41 @@ async def test_coh_summaries_group_by_tag_key_without_key(mock_context):
18581858

18591859
assert res['error_type'] == 'validation_error'
18601860
mock_summaries.assert_not_awaited()
1861+
1862+
1863+
async def _coh_served_description() -> str:
1864+
"""Return the cost-optimization description as served (reloaded with the real decorator).
1865+
1866+
Other tests reload the module with an identity decorator, which leaves a server
1867+
with no tools, so reload it here with the real one.
1868+
"""
1869+
from awslabs.billing_cost_management_mcp_server.tools import (
1870+
cost_optimization_hub_tools as coh_mod,
1871+
)
1872+
1873+
coh_mod = importlib.reload(coh_mod)
1874+
tool = await coh_mod.cost_optimization_hub_server.get_tool('cost-optimization')
1875+
assert tool is not None
1876+
return ' '.join((tool.description or '').split())
1877+
1878+
1879+
@pytest.mark.asyncio
1880+
async def test_description_does_not_route_trends_to_monthly_efficiency():
1881+
"""A Monthly efficiency point is one day's snapshot, so trend questions go to Daily."""
1882+
flat = await _coh_served_description()
1883+
assert 'month-over-month change' not in flat
1884+
assert 'its trend over time' not in flat
1885+
assert 'not a monthly average or total' in flat
1886+
assert 'last day of the month that has data' in flat
1887+
assert "For a trend or a change over time, use 'Daily'" in flat
1888+
1889+
1890+
@pytest.mark.asyncio
1891+
async def test_description_says_what_an_efficiency_point_covers():
1892+
"""Each point is a snapshot over trailing-30-day spend; ask Monthly only for completed months."""
1893+
flat = await _coh_served_description()
1894+
assert 'one-day snapshot, not a period total' in flat
1895+
assert 'the trailing 30 days of spend' in flat
1896+
assert 'Ask only for completed months' in flat
1897+
assert 'a current-month point would be partial' in flat
1898+
assert 'Only completed months are returned' not in flat

0 commit comments

Comments
 (0)