awslabs.cost-explorer-mcp-server 0.0.4__py3-none-any.whl → 0.0.6__py3-none-any.whl
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.
- awslabs/cost_explorer_mcp_server/comparison_handler.py +719 -0
- awslabs/cost_explorer_mcp_server/constants.py +106 -0
- awslabs/cost_explorer_mcp_server/cost_usage_handler.py +385 -0
- awslabs/cost_explorer_mcp_server/forecasting_handler.py +234 -0
- awslabs/cost_explorer_mcp_server/helpers.py +501 -68
- awslabs/cost_explorer_mcp_server/metadata_handler.py +88 -0
- awslabs/cost_explorer_mcp_server/models.py +70 -0
- awslabs/cost_explorer_mcp_server/server.py +60 -463
- awslabs/cost_explorer_mcp_server/utility_handler.py +50 -0
- {awslabs_cost_explorer_mcp_server-0.0.4.dist-info → awslabs_cost_explorer_mcp_server-0.0.6.dist-info}/METADATA +44 -14
- awslabs_cost_explorer_mcp_server-0.0.6.dist-info/RECORD +17 -0
- awslabs_cost_explorer_mcp_server-0.0.4.dist-info/RECORD +0 -10
- {awslabs_cost_explorer_mcp_server-0.0.4.dist-info → awslabs_cost_explorer_mcp_server-0.0.6.dist-info}/WHEEL +0 -0
- {awslabs_cost_explorer_mcp_server-0.0.4.dist-info → awslabs_cost_explorer_mcp_server-0.0.6.dist-info}/entry_points.txt +0 -0
- {awslabs_cost_explorer_mcp_server-0.0.4.dist-info → awslabs_cost_explorer_mcp_server-0.0.6.dist-info}/licenses/LICENSE +0 -0
- {awslabs_cost_explorer_mcp_server-0.0.4.dist-info → awslabs_cost_explorer_mcp_server-0.0.6.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Cost Explorer MCP server implementation.
|
|
16
|
+
|
|
17
|
+
Metadata tools for Cost Explorer MCP Server.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
from awslabs.cost_explorer_mcp_server.helpers import (
|
|
23
|
+
get_available_dimension_values,
|
|
24
|
+
get_available_tag_values,
|
|
25
|
+
)
|
|
26
|
+
from awslabs.cost_explorer_mcp_server.models import DateRange, DimensionKey
|
|
27
|
+
from loguru import logger
|
|
28
|
+
from mcp.server.fastmcp import Context
|
|
29
|
+
from pydantic import Field
|
|
30
|
+
from typing import Any, Dict
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Configure Loguru logging
|
|
34
|
+
logger.remove()
|
|
35
|
+
logger.add(sys.stderr, level=os.getenv('FASTMCP_LOG_LEVEL', 'WARNING'))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def get_dimension_values(
|
|
39
|
+
ctx: Context, date_range: DateRange, dimension: DimensionKey
|
|
40
|
+
) -> Dict[str, Any]:
|
|
41
|
+
"""Retrieve available dimension values for AWS Cost Explorer.
|
|
42
|
+
|
|
43
|
+
This tool retrieves all available and valid values for a specified dimension (e.g., SERVICE, REGION)
|
|
44
|
+
over a period of time. This is useful for validating filter values or exploring available options
|
|
45
|
+
for cost analysis.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
ctx: MCP context
|
|
49
|
+
date_range: The billing period start and end dates in YYYY-MM-DD format
|
|
50
|
+
dimension: The dimension key to retrieve values for (e.g., SERVICE, REGION, LINKED_ACCOUNT)
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dictionary containing the dimension name and list of available values
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
response = get_available_dimension_values(
|
|
57
|
+
dimension.dimension_key, date_range.start_date, date_range.end_date
|
|
58
|
+
)
|
|
59
|
+
return response
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f'Error getting dimension values for {dimension.dimension_key}: {e}')
|
|
62
|
+
return {'error': f'Error getting dimension values: {str(e)}'}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
async def get_tag_values(
|
|
66
|
+
ctx: Context,
|
|
67
|
+
date_range: DateRange,
|
|
68
|
+
tag_key: str = Field(..., description='The tag key to retrieve values for'),
|
|
69
|
+
) -> Dict[str, Any]:
|
|
70
|
+
"""Retrieve available tag values for AWS Cost Explorer.
|
|
71
|
+
|
|
72
|
+
This tool retrieves all available values for a specified tag key over a period of time.
|
|
73
|
+
This is useful for validating tag filter values or exploring available tag options for cost analysis.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
ctx: MCP context
|
|
77
|
+
date_range: The billing period start and end dates in YYYY-MM-DD format
|
|
78
|
+
tag_key: The tag key to retrieve values for
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Dictionary containing the tag key and list of available values
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
response = get_available_tag_values(tag_key, date_range.start_date, date_range.end_date)
|
|
85
|
+
return response
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.error(f'Error getting tag values for {tag_key}: {e}')
|
|
88
|
+
return {'error': f'Error getting tag values: {str(e)}'}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from awslabs.cost_explorer_mcp_server.constants import VALID_DIMENSIONS
|
|
16
|
+
from awslabs.cost_explorer_mcp_server.helpers import validate_date_format, validate_date_range
|
|
17
|
+
from pydantic import BaseModel, Field, field_validator
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
"""Data models and validation logic for Cost Explorer MCP Server.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DateRange(BaseModel):
|
|
25
|
+
"""Date range model for cost queries."""
|
|
26
|
+
|
|
27
|
+
start_date: str = Field(
|
|
28
|
+
description='The start date of the billing period in YYYY-MM-DD format. Defaults to last month, if not provided.'
|
|
29
|
+
)
|
|
30
|
+
end_date: str = Field(description='The end date of the billing period in YYYY-MM-DD format.')
|
|
31
|
+
|
|
32
|
+
@field_validator('start_date', 'end_date')
|
|
33
|
+
@classmethod
|
|
34
|
+
def validate_individual_dates(cls, v):
|
|
35
|
+
"""Validate that individual dates are in YYYY-MM-DD format and are valid dates."""
|
|
36
|
+
is_valid, error = validate_date_format(v)
|
|
37
|
+
if not is_valid:
|
|
38
|
+
raise ValueError(error)
|
|
39
|
+
return v
|
|
40
|
+
|
|
41
|
+
def model_post_init(self, __context):
|
|
42
|
+
"""Validate the date range after both dates are set."""
|
|
43
|
+
is_valid, error = validate_date_range(self.start_date, self.end_date)
|
|
44
|
+
if not is_valid:
|
|
45
|
+
raise ValueError(error)
|
|
46
|
+
|
|
47
|
+
def validate_with_granularity(self, granularity: str):
|
|
48
|
+
"""Validate the date range with granularity-specific constraints."""
|
|
49
|
+
is_valid, error = validate_date_range(self.start_date, self.end_date, granularity)
|
|
50
|
+
if not is_valid:
|
|
51
|
+
raise ValueError(error)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DimensionKey(BaseModel):
|
|
55
|
+
"""Dimension key model."""
|
|
56
|
+
|
|
57
|
+
dimension_key: str = Field(
|
|
58
|
+
description=f'The name of the dimension to retrieve values for. Valid values are {", ".join(VALID_DIMENSIONS)}.'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@field_validator('dimension_key')
|
|
62
|
+
@classmethod
|
|
63
|
+
def validate_dimension_key(cls, v):
|
|
64
|
+
"""Validate that the dimension key is supported by AWS Cost Explorer."""
|
|
65
|
+
dimension_upper = v.upper()
|
|
66
|
+
if dimension_upper not in VALID_DIMENSIONS:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Invalid dimension key '{v}'. Valid dimensions are: {', '.join(VALID_DIMENSIONS)}"
|
|
69
|
+
)
|
|
70
|
+
return v
|