awslabs.eks-mcp-server 0.1.1__py3-none-any.whl → 0.1.3__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/__init__.py +9 -6
- awslabs/eks_mcp_server/__init__.py +9 -6
- awslabs/eks_mcp_server/aws_helper.py +12 -8
- awslabs/eks_mcp_server/cloudwatch_handler.py +75 -77
- awslabs/eks_mcp_server/cloudwatch_metrics_guidance_handler.py +141 -0
- awslabs/eks_mcp_server/consts.py +9 -6
- awslabs/eks_mcp_server/data/eks_cloudwatch_metrics_guidance.json +287 -0
- awslabs/eks_mcp_server/eks_kb_handler.py +9 -6
- awslabs/eks_mcp_server/eks_stack_handler.py +38 -8
- awslabs/eks_mcp_server/iam_handler.py +14 -6
- awslabs/eks_mcp_server/k8s_apis.py +25 -14
- awslabs/eks_mcp_server/k8s_client_cache.py +9 -6
- awslabs/eks_mcp_server/k8s_handler.py +55 -6
- awslabs/eks_mcp_server/logging_helper.py +9 -6
- awslabs/eks_mcp_server/models.py +24 -10
- awslabs/eks_mcp_server/scripts/update_eks_cloudwatch_metrics_guidance.py +280 -0
- awslabs/eks_mcp_server/server.py +16 -7
- {awslabs_eks_mcp_server-0.1.1.dist-info → awslabs_eks_mcp_server-0.1.3.dist-info}/METADATA +170 -34
- awslabs_eks_mcp_server-0.1.3.dist-info/RECORD +26 -0
- awslabs_eks_mcp_server-0.1.1.dist-info/RECORD +0 -23
- {awslabs_eks_mcp_server-0.1.1.dist-info → awslabs_eks_mcp_server-0.1.3.dist-info}/WHEEL +0 -0
- {awslabs_eks_mcp_server-0.1.1.dist-info → awslabs_eks_mcp_server-0.1.3.dist-info}/entry_points.txt +0 -0
- {awslabs_eks_mcp_server-0.1.1.dist-info → awslabs_eks_mcp_server-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {awslabs_eks_mcp_server-0.1.1.dist-info → awslabs_eks_mcp_server-0.1.3.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
4
|
-
#
|
|
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
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
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.
|
|
11
14
|
|
|
12
15
|
"""Logging helper for the EKS MCP Server."""
|
|
13
16
|
|
awslabs/eks_mcp_server/models.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
4
|
-
#
|
|
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
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
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.
|
|
11
14
|
|
|
12
15
|
"""Data models for the EKS MCP Server."""
|
|
13
16
|
|
|
@@ -150,7 +153,7 @@ class CloudWatchLogsResponse(CallToolResult):
|
|
|
150
153
|
"""
|
|
151
154
|
|
|
152
155
|
resource_type: str = Field(..., description='Resource type (pod, node, container)')
|
|
153
|
-
resource_name: str = Field(
|
|
156
|
+
resource_name: Optional[str] = Field(None, description='Resource name')
|
|
154
157
|
cluster_name: str = Field(..., description='Name of the EKS cluster')
|
|
155
158
|
log_type: str = Field(
|
|
156
159
|
..., description='Log type (application, host, performance, control-plane, or custom)'
|
|
@@ -178,11 +181,9 @@ class CloudWatchMetricsResponse(CallToolResult):
|
|
|
178
181
|
"""Response model for get_cloudwatch_metrics tool.
|
|
179
182
|
|
|
180
183
|
This model contains the response from a CloudWatch metrics query,
|
|
181
|
-
including
|
|
184
|
+
including metric details, time range, and data points.
|
|
182
185
|
"""
|
|
183
186
|
|
|
184
|
-
resource_type: str = Field(..., description='Resource type (pod, node, container, cluster)')
|
|
185
|
-
resource_name: str = Field(..., description='Resource name')
|
|
186
187
|
cluster_name: str = Field(..., description='Name of the EKS cluster')
|
|
187
188
|
metric_name: str = Field(..., description='Metric name (e.g., cpu_usage_total, memory_rss)')
|
|
188
189
|
namespace: str = Field(..., description='CloudWatch namespace (e.g., ContainerInsights)')
|
|
@@ -269,3 +270,16 @@ class AddInlinePolicyResponse(CallToolResult):
|
|
|
269
270
|
permissions_added: Union[Dict[str, Any], List[Dict[str, Any]]] = Field(
|
|
270
271
|
..., description='Permissions to include in the policy (in JSON format)'
|
|
271
272
|
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class MetricsGuidanceResponse(CallToolResult):
|
|
276
|
+
"""Response model for get_eks_metrics_guidance tool.
|
|
277
|
+
|
|
278
|
+
This model contains the response from a metrics guidance query,
|
|
279
|
+
including resource type and available metrics with their details.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
resource_type: str = Field(
|
|
283
|
+
..., description='Resource type (cluster, node, pod, namespace, service)'
|
|
284
|
+
)
|
|
285
|
+
metrics: List[Dict[str, Any]] = Field(..., description='List of metrics with their details')
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Script to scrape CloudWatch metrics data from AWS documentation and update the metrics guidance JSON file.
|
|
17
|
+
|
|
18
|
+
This script fetches the EKS and Kubernetes Container Insights metrics table from the AWS documentation,
|
|
19
|
+
extracts the metric names, dimensions, and descriptions, and updates the eks_cloudwatch_metrics_guidance.json file.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import logging
|
|
24
|
+
import os
|
|
25
|
+
import re
|
|
26
|
+
import requests
|
|
27
|
+
from bs4 import BeautifulSoup, Tag
|
|
28
|
+
from typing import Any, Dict, List
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Configure logging
|
|
32
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
# URL of the AWS documentation page containing the metrics table
|
|
36
|
+
DOCS_URL = 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-EKS.html'
|
|
37
|
+
|
|
38
|
+
# Path to the metrics guidance JSON file (relative to the script location)
|
|
39
|
+
METRICS_FILE_PATH = os.path.join(
|
|
40
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
|
41
|
+
'data',
|
|
42
|
+
'eks_cloudwatch_metrics_guidance.json',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def fetch_documentation_page() -> str:
|
|
47
|
+
"""Fetch the AWS documentation page containing the metrics table.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
str: HTML content of the documentation page
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
response = requests.get(DOCS_URL, timeout=10)
|
|
54
|
+
response.raise_for_status()
|
|
55
|
+
return response.text
|
|
56
|
+
except requests.RequestException as e:
|
|
57
|
+
logger.error(f'Failed to fetch documentation page: {e}')
|
|
58
|
+
raise
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def parse_metrics_table(html_content: str) -> List[Dict[str, Any]]:
|
|
62
|
+
"""Parse the metrics table from the HTML content.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
html_content: HTML content of the documentation page
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
List[Dict[str, Any]]: List of metrics with their names, dimensions, and descriptions
|
|
69
|
+
"""
|
|
70
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
|
71
|
+
|
|
72
|
+
# Find the metrics table
|
|
73
|
+
# Use a function that returns a boolean to avoid type issues
|
|
74
|
+
def table_id_matcher(x: str) -> bool:
|
|
75
|
+
return bool(x and 'w420aac24b7c33c15b7' in x)
|
|
76
|
+
|
|
77
|
+
table = soup.find('table', id=table_id_matcher)
|
|
78
|
+
if not table:
|
|
79
|
+
logger.error('Metrics table not found in the documentation page')
|
|
80
|
+
raise ValueError('Metrics table not found')
|
|
81
|
+
|
|
82
|
+
metrics = []
|
|
83
|
+
rows = table.find_all('tr') if isinstance(table, Tag) else []
|
|
84
|
+
|
|
85
|
+
# Skip the header row
|
|
86
|
+
for row in rows[1:]:
|
|
87
|
+
cells = row.find_all('td') if isinstance(row, Tag) else []
|
|
88
|
+
if len(cells) == 3:
|
|
89
|
+
# Extract metric name
|
|
90
|
+
metric_name_cell = cells[0]
|
|
91
|
+
metric_name_element = None
|
|
92
|
+
if isinstance(metric_name_cell, Tag):
|
|
93
|
+
metric_name_element = metric_name_cell.find('code', attrs={'class': 'code'})
|
|
94
|
+
|
|
95
|
+
if not metric_name_element:
|
|
96
|
+
continue
|
|
97
|
+
|
|
98
|
+
metric_name = (
|
|
99
|
+
metric_name_element.text.strip() if hasattr(metric_name_element, 'text') else ''
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Extract dimensions
|
|
103
|
+
dimensions_cell = cells[1]
|
|
104
|
+
dimensions = []
|
|
105
|
+
|
|
106
|
+
# Find all paragraph elements in the dimensions cell
|
|
107
|
+
paragraphs = []
|
|
108
|
+
if isinstance(dimensions_cell, Tag):
|
|
109
|
+
paragraphs = dimensions_cell.find_all('p')
|
|
110
|
+
|
|
111
|
+
# Process each paragraph
|
|
112
|
+
for paragraph in paragraphs:
|
|
113
|
+
# Find all code elements within this paragraph
|
|
114
|
+
code_elements = []
|
|
115
|
+
if isinstance(paragraph, Tag):
|
|
116
|
+
code_elements = paragraph.find_all('code', attrs={'class': 'code'})
|
|
117
|
+
|
|
118
|
+
if len(code_elements) > 1:
|
|
119
|
+
# Multiple dimensions in a single paragraph - combine them
|
|
120
|
+
combined_dimensions = []
|
|
121
|
+
for code in code_elements:
|
|
122
|
+
if hasattr(code, 'text'):
|
|
123
|
+
combined_dimensions.append(code.text.strip())
|
|
124
|
+
|
|
125
|
+
# Join the dimensions with commas
|
|
126
|
+
if combined_dimensions:
|
|
127
|
+
dimensions.append(','.join(combined_dimensions))
|
|
128
|
+
elif len(code_elements) == 1:
|
|
129
|
+
# Single dimension in a paragraph
|
|
130
|
+
code = code_elements[0]
|
|
131
|
+
if hasattr(code, 'text'):
|
|
132
|
+
dimension_text = code.text.strip()
|
|
133
|
+
if ',' in dimension_text:
|
|
134
|
+
# Already comma-separated in the text
|
|
135
|
+
dimensions.append(dimension_text)
|
|
136
|
+
else:
|
|
137
|
+
dimensions.append(dimension_text)
|
|
138
|
+
|
|
139
|
+
# Also check for any code elements directly in the cell (not in paragraphs)
|
|
140
|
+
dimension_codes = []
|
|
141
|
+
if isinstance(dimensions_cell, Tag):
|
|
142
|
+
dimension_codes = dimensions_cell.find_all(
|
|
143
|
+
'code', attrs={'class': 'code'}, recursive=False
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
for dimension_code in dimension_codes:
|
|
147
|
+
if hasattr(dimension_code, 'text'):
|
|
148
|
+
dimension_text = dimension_code.text.strip()
|
|
149
|
+
if dimension_text and dimension_text not in dimensions:
|
|
150
|
+
dimensions.append(dimension_text)
|
|
151
|
+
|
|
152
|
+
# Extract description
|
|
153
|
+
description_cell = cells[2]
|
|
154
|
+
description_element = None
|
|
155
|
+
if isinstance(description_cell, Tag):
|
|
156
|
+
description_element = description_cell.find('p')
|
|
157
|
+
|
|
158
|
+
if not description_element:
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
# Get the description and normalize whitespace (replace multiple spaces with a single space)
|
|
162
|
+
description_text = (
|
|
163
|
+
description_element.text.strip() if hasattr(description_element, 'text') else ''
|
|
164
|
+
)
|
|
165
|
+
description = re.sub(r'\s+', ' ', description_text)
|
|
166
|
+
|
|
167
|
+
metrics.append(
|
|
168
|
+
{'description': description, 'dimensions': dimensions, 'name': metric_name}
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
return metrics
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def organize_metrics_by_resource_type(
|
|
175
|
+
metrics: List[Dict[str, Any]],
|
|
176
|
+
) -> Dict[str, Dict[str, List[Dict[str, Any]]]]:
|
|
177
|
+
"""Organize metrics by resource type based on their names.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
metrics: List of metrics with their names, dimensions, and descriptions
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Dict[str, Dict[str, List[Dict[str, Any]]]]: Metrics organized by resource type
|
|
184
|
+
"""
|
|
185
|
+
resource_types = {'cluster': [], 'namespace': [], 'node': [], 'pod': [], 'service': []}
|
|
186
|
+
|
|
187
|
+
for metric in metrics:
|
|
188
|
+
name = metric['name']
|
|
189
|
+
|
|
190
|
+
# Determine resource type based on metric name prefix
|
|
191
|
+
if name.startswith('cluster_'):
|
|
192
|
+
resource_type = 'cluster'
|
|
193
|
+
elif name.startswith('namespace_'):
|
|
194
|
+
resource_type = 'namespace'
|
|
195
|
+
elif name.startswith('node_'):
|
|
196
|
+
resource_type = 'node'
|
|
197
|
+
elif name.startswith('pod_'):
|
|
198
|
+
resource_type = 'pod'
|
|
199
|
+
elif name.startswith('service_'):
|
|
200
|
+
resource_type = 'service'
|
|
201
|
+
else:
|
|
202
|
+
logger.warning(f'Unknown resource type for metric: {name}')
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
resource_types[resource_type].append(metric)
|
|
206
|
+
|
|
207
|
+
# Convert to the required format
|
|
208
|
+
result = {}
|
|
209
|
+
for resource_type, metrics_list in resource_types.items():
|
|
210
|
+
result[resource_type] = {'metrics': metrics_list}
|
|
211
|
+
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def load_existing_metrics() -> Dict[str, Any]:
|
|
216
|
+
"""Load existing metrics from the JSON file.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Dict[str, Any]: Existing metrics data
|
|
220
|
+
"""
|
|
221
|
+
try:
|
|
222
|
+
with open(METRICS_FILE_PATH, 'r') as f:
|
|
223
|
+
return json.load(f)
|
|
224
|
+
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
225
|
+
logger.warning(f'Failed to load existing metrics file: {e}')
|
|
226
|
+
return {}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def save_metrics(metrics_data: Dict[str, Any]) -> None:
|
|
230
|
+
"""Save metrics data to the JSON file.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
metrics_data: Metrics data to save
|
|
234
|
+
"""
|
|
235
|
+
try:
|
|
236
|
+
with open(METRICS_FILE_PATH, 'w') as f:
|
|
237
|
+
json.dump(metrics_data, f, indent=2)
|
|
238
|
+
logger.info(f'Metrics data saved to {METRICS_FILE_PATH}')
|
|
239
|
+
except IOError as e:
|
|
240
|
+
logger.error(f'Failed to save metrics data: {e}')
|
|
241
|
+
raise
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def main() -> None:
|
|
245
|
+
"""Main function to update the metrics guidance JSON file."""
|
|
246
|
+
logger.info('Starting CloudWatch metrics guidance update')
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
# Fetch the documentation page
|
|
250
|
+
logger.info(f'Fetching documentation from {DOCS_URL}')
|
|
251
|
+
html_content = fetch_documentation_page()
|
|
252
|
+
|
|
253
|
+
# Parse the metrics table
|
|
254
|
+
logger.info('Parsing metrics table')
|
|
255
|
+
metrics = parse_metrics_table(html_content)
|
|
256
|
+
logger.info(f'Found {len(metrics)} metrics in the documentation')
|
|
257
|
+
|
|
258
|
+
# Organize metrics by resource type
|
|
259
|
+
logger.info('Organizing metrics by resource type')
|
|
260
|
+
organized_metrics = organize_metrics_by_resource_type(metrics)
|
|
261
|
+
|
|
262
|
+
# Load existing metrics for comparison
|
|
263
|
+
existing_metrics = load_existing_metrics()
|
|
264
|
+
|
|
265
|
+
# Check if there are any changes
|
|
266
|
+
if existing_metrics == organized_metrics:
|
|
267
|
+
logger.info('No changes detected in metrics data')
|
|
268
|
+
else:
|
|
269
|
+
# Save the updated metrics
|
|
270
|
+
logger.info('Changes detected in metrics data, updating file')
|
|
271
|
+
save_metrics(organized_metrics)
|
|
272
|
+
logger.info('Metrics guidance JSON file updated successfully')
|
|
273
|
+
|
|
274
|
+
except Exception as e:
|
|
275
|
+
logger.error(f'Failed to update metrics guidance: {e}')
|
|
276
|
+
raise
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
if __name__ == '__main__':
|
|
280
|
+
main()
|
awslabs/eks_mcp_server/server.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
4
|
-
#
|
|
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
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
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.
|
|
11
14
|
|
|
12
15
|
"""awslabs EKS MCP Server implementation.
|
|
13
16
|
|
|
@@ -22,6 +25,7 @@ Environment Variables:
|
|
|
22
25
|
|
|
23
26
|
import argparse
|
|
24
27
|
from awslabs.eks_mcp_server.cloudwatch_handler import CloudWatchHandler
|
|
28
|
+
from awslabs.eks_mcp_server.cloudwatch_metrics_guidance_handler import CloudWatchMetricsHandler
|
|
25
29
|
from awslabs.eks_mcp_server.eks_kb_handler import EKSKnowledgeBaseHandler
|
|
26
30
|
from awslabs.eks_mcp_server.eks_stack_handler import EksStackHandler
|
|
27
31
|
from awslabs.eks_mcp_server.iam_handler import IAMHandler
|
|
@@ -36,6 +40,10 @@ SERVER_INSTRUCTIONS = """
|
|
|
36
40
|
|
|
37
41
|
This MCP server provides tools for managing Amazon EKS clusters and is the preferred mechanism for creating new EKS clusters.
|
|
38
42
|
|
|
43
|
+
## IMPORTANT: Use MCP Tools for EKS and Kubernetes Operations
|
|
44
|
+
|
|
45
|
+
DO NOT use standard EKS and Kubernetes CLI commands (aws eks, eksctl, kubectl). Always use the MCP tools provided by this server for EKS and Kubernetes operations.
|
|
46
|
+
|
|
39
47
|
## Usage Notes
|
|
40
48
|
|
|
41
49
|
- By default, the server runs in read-only mode. Use the `--allow-write` flag to enable write operations.
|
|
@@ -57,7 +65,7 @@ This MCP server provides tools for managing Amazon EKS clusters and is the prefe
|
|
|
57
65
|
1. Check pod status: `list_k8s_resources(cluster_name='my-cluster', kind='Pod', api_version='v1', namespace='default', field_selector='metadata.name=my-pod')`
|
|
58
66
|
2. Get pod events: `get_k8s_events(cluster_name='my-cluster', kind='Pod', name='my-pod', namespace='default')`
|
|
59
67
|
3. Check pod logs: `get_pod_logs(cluster_name='my-cluster', namespace='default', pod_name='my-pod')`
|
|
60
|
-
4. Monitor metrics: `get_cloudwatch_metrics(
|
|
68
|
+
4. Monitor metrics: `get_cloudwatch_metrics(cluster_name='my-cluster', metric_name='cpu_usage_total', namespace='ContainerInsights', dimensions={'ClusterName': 'my-cluster', 'PodName': 'my-pod', 'Namespace': 'default'})`
|
|
61
69
|
5. Search troubleshooting guide: `search_eks_troubleshoot_guide(query='pod pending')`
|
|
62
70
|
|
|
63
71
|
## Best Practices
|
|
@@ -140,6 +148,7 @@ def main():
|
|
|
140
148
|
EksStackHandler(mcp, allow_write)
|
|
141
149
|
K8sHandler(mcp, allow_write, allow_sensitive_data_access)
|
|
142
150
|
IAMHandler(mcp, allow_write)
|
|
151
|
+
CloudWatchMetricsHandler(mcp)
|
|
143
152
|
|
|
144
153
|
# Run server
|
|
145
154
|
mcp.run()
|