awslabs.eks-mcp-server 0.1.12__tar.gz → 0.1.13__tar.gz

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.
Files changed (50) hide show
  1. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/.gitignore +1 -0
  2. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/PKG-INFO +41 -3
  3. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/README.md +40 -2
  4. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/__init__.py +1 -1
  5. awslabs_eks_mcp_server-0.1.13/awslabs/eks_mcp_server/insights_handler.py +342 -0
  6. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/k8s_apis.py +4 -0
  7. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/k8s_handler.py +6 -0
  8. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/models.py +78 -0
  9. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/server.py +4 -0
  10. awslabs_eks_mcp_server-0.1.13/awslabs/eks_mcp_server/vpc_config_handler.py +425 -0
  11. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/pyproject.toml +1 -1
  12. awslabs_eks_mcp_server-0.1.13/tests/test_insights_handler.py +493 -0
  13. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_k8s_apis.py +2 -0
  14. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_k8s_handler.py +3 -0
  15. awslabs_eks_mcp_server-0.1.13/tests/test_vpc_config_handler.py +1052 -0
  16. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/uv.lock +1 -1
  17. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/.python-version +0 -0
  18. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/CHANGELOG.md +0 -0
  19. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/Dockerfile +0 -0
  20. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/LICENSE +0 -0
  21. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/NOTICE +0 -0
  22. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/__init__.py +0 -0
  23. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/aws_helper.py +0 -0
  24. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/cloudwatch_handler.py +0 -0
  25. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/cloudwatch_metrics_guidance_handler.py +0 -0
  26. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/consts.py +0 -0
  27. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/data/eks_cloudwatch_metrics_guidance.json +0 -0
  28. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/eks_kb_handler.py +0 -0
  29. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/eks_stack_handler.py +0 -0
  30. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/iam_handler.py +0 -0
  31. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/k8s_client_cache.py +0 -0
  32. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/logging_helper.py +0 -0
  33. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/scripts/update_eks_cloudwatch_metrics_guidance.py +0 -0
  34. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/templates/eks-templates/eks-with-vpc.yaml +0 -0
  35. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/templates/k8s-templates/deployment.yaml +0 -0
  36. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/awslabs/eks_mcp_server/templates/k8s-templates/service.yaml +0 -0
  37. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/docker-healthcheck.sh +0 -0
  38. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_aws_helper.py +0 -0
  39. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_cloudwatch_handler.py +0 -0
  40. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_cloudwatch_metrics_guidance_handler.py +0 -0
  41. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_eks_kb_handler.py +0 -0
  42. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_eks_stack_handler.py +0 -0
  43. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_iam_handler.py +0 -0
  44. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_init.py +0 -0
  45. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_k8s_client_cache.py +0 -0
  46. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_logging_helper.py +0 -0
  47. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_main.py +0 -0
  48. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_models.py +0 -0
  49. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/tests/test_server.py +0 -0
  50. {awslabs_eks_mcp_server-0.1.12 → awslabs_eks_mcp_server-0.1.13}/uv-requirements.txt +0 -0
@@ -40,6 +40,7 @@ ENV/
40
40
  .coverage.*
41
41
  htmlcov/
42
42
  .pytest_cache/
43
+ tmp/
43
44
 
44
45
  # Ruff
45
46
  .ruff_cache/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.eks-mcp-server
3
- Version: 0.1.12
3
+ Version: 0.1.13
4
4
  Summary: An AWS Labs Model Context Protocol (MCP) server for EKS
5
5
  Project-URL: homepage, https://awslabs.github.io/mcp/
6
6
  Project-URL: docs, https://awslabs.github.io/mcp/servers/eks-mcp-server/
@@ -69,6 +69,11 @@ For read operations, the following permissions are required:
69
69
  "Effect": "Allow",
70
70
  "Action": [
71
71
  "eks:DescribeCluster",
72
+ "eks:DescribeInsight",
73
+ "eks:ListInsights",
74
+ "ec2:DescribeVpcs",
75
+ "ec2:DescribeSubnets",
76
+ "ec2:DescribeRouteTables",
72
77
  "cloudformation:DescribeStacks",
73
78
  "cloudwatch:GetMetricData",
74
79
  "logs:StartQuery",
@@ -417,7 +422,7 @@ Features:
417
422
 
418
423
  Parameters:
419
424
 
420
- * cluster_name, pod_name, namespace, container_name (optional), since_seconds (optional), tail_lines (optional), limit_bytes (optional)
425
+ * cluster_name, pod_name, namespace, container_name (optional), since_seconds (optional), tail_lines (optional), limit_bytes (optional), previous (optional)
421
426
 
422
427
  #### `get_k8s_events`
423
428
 
@@ -433,6 +438,22 @@ Parameters:
433
438
 
434
439
  * cluster_name, kind, name, namespace (optional)
435
440
 
441
+ #### `get_eks_vpc_config`
442
+
443
+ Retrieves comprehensive VPC configuration details for EKS clusters, with support for hybrid node setups.
444
+
445
+ Features:
446
+
447
+ * Returns detailed VPC configuration including CIDR blocks, route tables, and subnet information
448
+ * Automatically identifies and includes remote node and pod CIDR configurations for hybrid node setups
449
+ * Validates subnet capacity for EKS networking requirements
450
+ * Flags subnets in disallowed availability zones that can't be used with EKS
451
+ * Requires `--allow-sensitive-data-access` server flag to be enabled
452
+
453
+ Parameters:
454
+
455
+ * cluster_name, vpc_id (optional)
456
+
436
457
  ### CloudWatch Integration
437
458
 
438
459
  #### `get_cloudwatch_logs`
@@ -536,6 +557,23 @@ Parameters:
536
557
 
537
558
  * query
538
559
 
560
+ #### `get_eks_insights`
561
+
562
+ Retrieves Amazon EKS Insights that identify potential issues with your EKS cluster configuration and upgrade readiness.
563
+
564
+ Features:
565
+
566
+ * Returns insights in two categories: MISCONFIGURATION and UPGRADE_READINESS (for upgrade blockers)
567
+ * Supports both list mode (all insights) and detail mode (specific insight with recommendations)
568
+ * Includes status, descriptions, and timestamps for each insight
569
+ * Provides detailed recommendations for addressing identified issues when using detail mode
570
+ * Supports optional filtering by insight category
571
+ * Requires `--allow-sensitive-data-access` server flag to be enabled
572
+
573
+ Parameters:
574
+
575
+ * cluster_name, insight_id (optional), category (optional), next_token (optional)
576
+
539
577
 
540
578
  ## Security & permissions
541
579
 
@@ -567,7 +605,7 @@ When using the EKS MCP Server, consider the following:
567
605
 
568
606
  The EKS MCP Server can be used for production environments with proper security controls in place. The server runs in read-only mode by default, which is recommended and considered generally safer for production environments. Only explicitly enable write access when necessary. Below are the EKS MCP server tools available in read-only versus write-access mode:
569
607
 
570
- * **Read-only mode (default)**: `manage_eks_stacks` (with operation="describe"), `manage_k8s_resource` (with operation="read"), `list_k8s_resources`, `get_pod_logs`, `get_k8s_events`, `get_cloudwatch_logs`, `get_cloudwatch_metrics`, `get_policies_for_role`, `search_eks_troubleshoot_guide`, `list_api_versions`.
608
+ * **Read-only mode (default)**: `manage_eks_stacks` (with operation="describe"), `manage_k8s_resource` (with operation="read"), `list_k8s_resources`, `get_pod_logs`, `get_k8s_events`, `get_cloudwatch_logs`, `get_cloudwatch_metrics`, `get_policies_for_role`, `search_eks_troubleshoot_guide`, `list_api_versions`, `get_eks_vpc_config`, `get_eks_insights`.
571
609
  * **Write-access mode**: (require `--allow-write`): `manage_eks_stacks` (with "generate", "deploy", "delete"), `manage_k8s_resource` (with "create", "replace", "patch", "delete"), `apply_yaml`, `generate_app_manifest`, `add_inline_policy`.
572
610
 
573
611
  #### `autoApprove` (optional)
@@ -35,6 +35,11 @@ For read operations, the following permissions are required:
35
35
  "Effect": "Allow",
36
36
  "Action": [
37
37
  "eks:DescribeCluster",
38
+ "eks:DescribeInsight",
39
+ "eks:ListInsights",
40
+ "ec2:DescribeVpcs",
41
+ "ec2:DescribeSubnets",
42
+ "ec2:DescribeRouteTables",
38
43
  "cloudformation:DescribeStacks",
39
44
  "cloudwatch:GetMetricData",
40
45
  "logs:StartQuery",
@@ -383,7 +388,7 @@ Features:
383
388
 
384
389
  Parameters:
385
390
 
386
- * cluster_name, pod_name, namespace, container_name (optional), since_seconds (optional), tail_lines (optional), limit_bytes (optional)
391
+ * cluster_name, pod_name, namespace, container_name (optional), since_seconds (optional), tail_lines (optional), limit_bytes (optional), previous (optional)
387
392
 
388
393
  #### `get_k8s_events`
389
394
 
@@ -399,6 +404,22 @@ Parameters:
399
404
 
400
405
  * cluster_name, kind, name, namespace (optional)
401
406
 
407
+ #### `get_eks_vpc_config`
408
+
409
+ Retrieves comprehensive VPC configuration details for EKS clusters, with support for hybrid node setups.
410
+
411
+ Features:
412
+
413
+ * Returns detailed VPC configuration including CIDR blocks, route tables, and subnet information
414
+ * Automatically identifies and includes remote node and pod CIDR configurations for hybrid node setups
415
+ * Validates subnet capacity for EKS networking requirements
416
+ * Flags subnets in disallowed availability zones that can't be used with EKS
417
+ * Requires `--allow-sensitive-data-access` server flag to be enabled
418
+
419
+ Parameters:
420
+
421
+ * cluster_name, vpc_id (optional)
422
+
402
423
  ### CloudWatch Integration
403
424
 
404
425
  #### `get_cloudwatch_logs`
@@ -502,6 +523,23 @@ Parameters:
502
523
 
503
524
  * query
504
525
 
526
+ #### `get_eks_insights`
527
+
528
+ Retrieves Amazon EKS Insights that identify potential issues with your EKS cluster configuration and upgrade readiness.
529
+
530
+ Features:
531
+
532
+ * Returns insights in two categories: MISCONFIGURATION and UPGRADE_READINESS (for upgrade blockers)
533
+ * Supports both list mode (all insights) and detail mode (specific insight with recommendations)
534
+ * Includes status, descriptions, and timestamps for each insight
535
+ * Provides detailed recommendations for addressing identified issues when using detail mode
536
+ * Supports optional filtering by insight category
537
+ * Requires `--allow-sensitive-data-access` server flag to be enabled
538
+
539
+ Parameters:
540
+
541
+ * cluster_name, insight_id (optional), category (optional), next_token (optional)
542
+
505
543
 
506
544
  ## Security & permissions
507
545
 
@@ -533,7 +571,7 @@ When using the EKS MCP Server, consider the following:
533
571
 
534
572
  The EKS MCP Server can be used for production environments with proper security controls in place. The server runs in read-only mode by default, which is recommended and considered generally safer for production environments. Only explicitly enable write access when necessary. Below are the EKS MCP server tools available in read-only versus write-access mode:
535
573
 
536
- * **Read-only mode (default)**: `manage_eks_stacks` (with operation="describe"), `manage_k8s_resource` (with operation="read"), `list_k8s_resources`, `get_pod_logs`, `get_k8s_events`, `get_cloudwatch_logs`, `get_cloudwatch_metrics`, `get_policies_for_role`, `search_eks_troubleshoot_guide`, `list_api_versions`.
574
+ * **Read-only mode (default)**: `manage_eks_stacks` (with operation="describe"), `manage_k8s_resource` (with operation="read"), `list_k8s_resources`, `get_pod_logs`, `get_k8s_events`, `get_cloudwatch_logs`, `get_cloudwatch_metrics`, `get_policies_for_role`, `search_eks_troubleshoot_guide`, `list_api_versions`, `get_eks_vpc_config`, `get_eks_insights`.
537
575
  * **Write-access mode**: (require `--allow-write`): `manage_eks_stacks` (with "generate", "deploy", "delete"), `manage_k8s_resource` (with "create", "replace", "patch", "delete"), `apply_yaml`, `generate_app_manifest`, `add_inline_policy`.
538
576
 
539
577
  #### `autoApprove` (optional)
@@ -14,4 +14,4 @@
14
14
 
15
15
  """awslabs.eks-mcp-server"""
16
16
 
17
- __version__ = '0.1.12'
17
+ __version__ = '0.1.13'
@@ -0,0 +1,342 @@
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
+ """Insights handler for the EKS MCP Server."""
16
+
17
+ from awslabs.eks_mcp_server.aws_helper import AwsHelper
18
+ from awslabs.eks_mcp_server.logging_helper import LogLevel, log_with_request_id
19
+ from awslabs.eks_mcp_server.models import (
20
+ EksInsightItem,
21
+ EksInsightsResponse,
22
+ EksInsightStatus,
23
+ )
24
+ from datetime import datetime
25
+ from mcp.server.fastmcp import Context
26
+ from mcp.types import TextContent
27
+ from pydantic import Field
28
+ from typing import Any, Optional
29
+
30
+
31
+ class InsightsHandler:
32
+ """Handler for Amazon EKS Insights.
33
+
34
+ This class provides tools for retrieving and analyzing insights about
35
+ EKS cluster configuration and upgrade readiness.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ mcp,
41
+ allow_sensitive_data_access: bool = False,
42
+ ):
43
+ """Initialize the Insights handler.
44
+
45
+ Args:
46
+ mcp: The MCP server instance
47
+ allow_sensitive_data_access: Whether to allow access to sensitive data (default: False)
48
+ """
49
+ self.mcp = mcp
50
+ self.allow_sensitive_data_access = allow_sensitive_data_access
51
+
52
+ # Register tools
53
+ self.mcp.tool(name='get_eks_insights')(self.get_eks_insights)
54
+
55
+ # Initialize AWS clients
56
+ self.eks_client = AwsHelper.create_boto3_client('eks')
57
+
58
+ # EKS Insights tool
59
+ async def get_eks_insights(
60
+ self,
61
+ ctx: Context,
62
+ cluster_name: str = Field(..., description='Name of the EKS cluster'),
63
+ insight_id: Optional[str] = Field(
64
+ None,
65
+ description='ID of a specific insight to get detailed information for. If provided, returns detailed information about this specific insight.',
66
+ ),
67
+ category: Optional[str] = Field(
68
+ None,
69
+ description='Filter insights by category (e.g., "MISCONFIGURATION" or "UPGRADE_READINESS")',
70
+ ),
71
+ next_token: Optional[str] = Field(
72
+ None,
73
+ description='Token for pagination to get the next set of results',
74
+ ),
75
+ ) -> EksInsightsResponse:
76
+ """Get EKS Insights for cluster configuration and upgrade readiness.
77
+
78
+ This tool retrieves Amazon EKS Insights that identify potential issues with
79
+ your EKS cluster. These insights help identify both cluster configuration issues
80
+ and upgrade readiness concerns that might affect hybrid nodes functionality.
81
+
82
+ Amazon EKS provides two types of insights:
83
+ - MISCONFIGURATION insights: Identify misconfigurations in your EKS cluster setup
84
+ - UPGRADE_READINESS insights: Identify issues that could prevent successful cluster upgrades
85
+
86
+ When used without an insight_id, it returns a list of all insights.
87
+ When used with an insight_id, it returns detailed information about
88
+ that specific insight, including recommendations.
89
+
90
+ ## Requirements
91
+ - The server must be run with the `--allow-sensitive-data-access` flag
92
+
93
+ ## Response Information
94
+ The response includes insight details such as status, description, and
95
+ recommendations for addressing identified issues.
96
+
97
+ ## Usage Tips
98
+ - Review MISCONFIGURATION insights to identify cluster misconfigurations
99
+ - Check UPGRADE_READINESS insights before upgrading your cluster
100
+ - Pay special attention to insights with FAILING status
101
+ - Focus on insights related to node and network configuration for hybrid nodes
102
+
103
+ Args:
104
+ ctx: MCP context
105
+ cluster_name: Name of the EKS cluster
106
+ insight_id: Optional ID of a specific insight to get detailed information for
107
+ category: Optional category to filter insights by (e.g., "MISCONFIGURATION" or "UPGRADE_READINESS")
108
+ next_token: Optional token for pagination to get the next set of results
109
+
110
+ Returns:
111
+ EksInsightsResponse with insights information
112
+ """
113
+ # Extract values from Field objects before passing them to the implementation method
114
+ cluster_name_value = cluster_name
115
+ insight_id_value = insight_id
116
+ category_value = category
117
+ next_token_value = next_token
118
+
119
+ # Delegate to the implementation method with extracted values
120
+ return await self._get_eks_insights_impl(
121
+ ctx, cluster_name_value, insight_id_value, category_value, next_token_value
122
+ )
123
+
124
+ async def _get_eks_insights_impl(
125
+ self,
126
+ ctx: Context,
127
+ cluster_name: str,
128
+ insight_id: Optional[str] = None,
129
+ category: Optional[str] = None,
130
+ next_token: Optional[str] = None,
131
+ ) -> EksInsightsResponse:
132
+ """Internal implementation of get_eks_insights."""
133
+ try:
134
+ # Always use the default EKS client
135
+ eks_client = self.eks_client
136
+
137
+ # Determine operation mode based on whether insight_id is provided
138
+ detail_mode = insight_id is not None
139
+
140
+ if detail_mode:
141
+ # Get details for a specific insight
142
+ return await self._get_insight_detail(
143
+ ctx, eks_client, cluster_name, insight_id, next_token
144
+ )
145
+ else:
146
+ # List all insights with optional category filter
147
+ return await self._list_insights(
148
+ ctx, eks_client, cluster_name, category, next_token
149
+ )
150
+
151
+ except Exception as e:
152
+ error_message = f'Error processing EKS insights request: {str(e)}'
153
+ log_with_request_id(ctx, LogLevel.ERROR, error_message)
154
+ return EksInsightsResponse(
155
+ isError=True,
156
+ content=[TextContent(type='text', text=error_message)],
157
+ cluster_name=cluster_name,
158
+ insights=[],
159
+ next_token=None,
160
+ detail_mode=(insight_id is not None),
161
+ )
162
+
163
+ async def _get_insight_detail(
164
+ self,
165
+ ctx: Context,
166
+ eks_client,
167
+ cluster_name: str,
168
+ insight_id: str,
169
+ next_token: Optional[str] = None,
170
+ ) -> EksInsightsResponse:
171
+ """Get details for a specific EKS insight."""
172
+ log_with_request_id(
173
+ ctx,
174
+ LogLevel.INFO,
175
+ f'Getting details for insight {insight_id} in cluster {cluster_name}',
176
+ )
177
+
178
+ try:
179
+ response = eks_client.describe_insight(id=insight_id, clusterName=cluster_name)
180
+
181
+ # Extract and format the insight details
182
+ if 'insight' in response:
183
+ insight_data = response['insight']
184
+
185
+ # Create insight status object
186
+ status_obj = EksInsightStatus(
187
+ status=insight_data.get('insightStatus', {}).get('status', 'UNKNOWN'),
188
+ reason=insight_data.get('insightStatus', {}).get('reason', ''),
189
+ )
190
+
191
+ # Handle datetime objects for timestamps
192
+ last_refresh_time = insight_data.get('lastRefreshTime', 0)
193
+ if isinstance(last_refresh_time, datetime):
194
+ last_refresh_time = last_refresh_time.timestamp()
195
+
196
+ last_transition_time = insight_data.get('lastTransitionTime', 0)
197
+ if isinstance(last_transition_time, datetime):
198
+ last_transition_time = last_transition_time.timestamp()
199
+
200
+ # Convert insight to EksInsightItem format
201
+ insight_item = EksInsightItem(
202
+ id=insight_data.get('id', ''),
203
+ name=insight_data.get('name', ''),
204
+ category=insight_data.get('category', ''),
205
+ kubernetes_version=insight_data.get('kubernetesVersion'),
206
+ last_refresh_time=last_refresh_time,
207
+ last_transition_time=last_transition_time,
208
+ description=insight_data.get('description', ''),
209
+ insight_status=status_obj,
210
+ recommendation=insight_data.get('recommendation'),
211
+ additional_info=insight_data.get('additionalInfo', {}),
212
+ resources=insight_data.get('resources', []),
213
+ category_specific_summary=insight_data.get('categorySpecificSummary', {}),
214
+ )
215
+
216
+ success_message = f'Successfully retrieved details for insight {insight_id}'
217
+ return EksInsightsResponse(
218
+ isError=False,
219
+ content=[TextContent(type='text', text=success_message)],
220
+ cluster_name=cluster_name,
221
+ insights=[insight_item],
222
+ next_token=None, # No pagination for detail view
223
+ detail_mode=True,
224
+ )
225
+ else:
226
+ error_message = f'No insight details found for ID {insight_id}'
227
+ log_with_request_id(ctx, LogLevel.WARNING, error_message)
228
+ return EksInsightsResponse(
229
+ isError=True,
230
+ content=[TextContent(type='text', text=error_message)],
231
+ cluster_name=cluster_name,
232
+ insights=[],
233
+ next_token=None,
234
+ detail_mode=True,
235
+ )
236
+
237
+ except Exception as e:
238
+ error_message = f'Error retrieving insight details: {str(e)}'
239
+ log_with_request_id(ctx, LogLevel.ERROR, error_message)
240
+ return EksInsightsResponse(
241
+ isError=True,
242
+ content=[TextContent(type='text', text=error_message)],
243
+ cluster_name=cluster_name,
244
+ insights=[],
245
+ next_token=None,
246
+ detail_mode=True,
247
+ )
248
+
249
+ async def _list_insights(
250
+ self,
251
+ ctx: Context,
252
+ eks_client,
253
+ cluster_name: str,
254
+ category: Optional[str] = None,
255
+ next_token: Optional[str] = None,
256
+ ) -> EksInsightsResponse:
257
+ """List EKS insights for a cluster with optional category filtering."""
258
+ log_with_request_id(ctx, LogLevel.INFO, f'Listing insights for cluster {cluster_name}')
259
+
260
+ try:
261
+ # Build the list_insights parameters
262
+ list_params: dict[str, Any] = {'clusterName': cluster_name}
263
+
264
+ # Add category filter if provided
265
+ if category:
266
+ log_with_request_id(
267
+ ctx, LogLevel.INFO, f'Filtering insights by category: {category}'
268
+ )
269
+ # Use the filter parameter with the correct structure
270
+ list_params['filter'] = {'categories': [category]}
271
+
272
+ # Add next_token if provided
273
+ if next_token:
274
+ log_with_request_id(
275
+ ctx, LogLevel.INFO, 'Using pagination token for next page of results'
276
+ )
277
+ list_params['nextToken'] = next_token
278
+
279
+ response = eks_client.list_insights(**list_params)
280
+
281
+ # Extract and format the insights
282
+ insight_items = []
283
+
284
+ if 'insights' in response:
285
+ for insight_data in response['insights']:
286
+ # Create insight status object
287
+ status_obj = EksInsightStatus(
288
+ status=insight_data.get('insightStatus', {}).get('status', 'UNKNOWN'),
289
+ reason=insight_data.get('insightStatus', {}).get('reason', ''),
290
+ )
291
+
292
+ # Handle datetime objects for timestamps
293
+ last_refresh_time = insight_data.get('lastRefreshTime', 0)
294
+ if isinstance(last_refresh_time, datetime):
295
+ last_refresh_time = last_refresh_time.timestamp()
296
+
297
+ last_transition_time = insight_data.get('lastTransitionTime', 0)
298
+ if isinstance(last_transition_time, datetime):
299
+ last_transition_time = last_transition_time.timestamp()
300
+
301
+ # Convert insight to EksInsightItem format
302
+ insight_item = EksInsightItem(
303
+ id=insight_data.get('id', ''),
304
+ name=insight_data.get('name', ''),
305
+ category=insight_data.get('category', ''),
306
+ kubernetes_version=insight_data.get('kubernetesVersion'),
307
+ last_refresh_time=last_refresh_time,
308
+ last_transition_time=last_transition_time,
309
+ description=insight_data.get('description', ''),
310
+ insight_status=status_obj,
311
+ # List mode doesn't include these fields
312
+ recommendation=None,
313
+ additional_info=None,
314
+ resources=None,
315
+ category_specific_summary=None,
316
+ )
317
+
318
+ insight_items.append(insight_item)
319
+
320
+ success_message = (
321
+ f'Successfully retrieved {len(insight_items)} insights for cluster {cluster_name}'
322
+ )
323
+ return EksInsightsResponse(
324
+ isError=False,
325
+ content=[TextContent(type='text', text=success_message)],
326
+ cluster_name=cluster_name,
327
+ insights=insight_items,
328
+ next_token=response.get('nextToken'),
329
+ detail_mode=False,
330
+ )
331
+
332
+ except Exception as e:
333
+ error_message = f'Error listing insights: {str(e)}'
334
+ log_with_request_id(ctx, LogLevel.ERROR, error_message)
335
+ return EksInsightsResponse(
336
+ isError=True,
337
+ content=[TextContent(type='text', text=error_message)],
338
+ cluster_name=cluster_name,
339
+ insights=[],
340
+ next_token=None,
341
+ detail_mode=False,
342
+ )
@@ -418,6 +418,7 @@ class K8sApis:
418
418
  since_seconds: Optional[int] = None,
419
419
  tail_lines: Optional[int] = None,
420
420
  limit_bytes: Optional[int] = None,
421
+ previous: Optional[bool] = None,
421
422
  ) -> str:
422
423
  """Get logs from a pod.
423
424
 
@@ -428,6 +429,7 @@ class K8sApis:
428
429
  since_seconds: Only return logs newer than this many seconds (optional)
429
430
  tail_lines: Number of lines to return from the end of the logs (optional)
430
431
  limit_bytes: Maximum number of bytes to return (optional)
432
+ previous: Return previous terminated container logs (optional)
431
433
 
432
434
  Returns:
433
435
  Pod logs as a string
@@ -448,6 +450,8 @@ class K8sApis:
448
450
  params['tail_lines'] = tail_lines
449
451
  if limit_bytes:
450
452
  params['limit_bytes'] = limit_bytes
453
+ if previous:
454
+ params['previous'] = previous
451
455
 
452
456
  # Call the read_namespaced_pod_log method
453
457
  logs_response = core_v1_api.read_namespaced_pod_log(
@@ -878,6 +878,10 @@ class K8sHandler:
878
878
  10240,
879
879
  description='Maximum number of bytes to return. Default: 10KB (10240 bytes). Prevents retrieving extremely large log files.',
880
880
  ),
881
+ previous: bool = Field(
882
+ False,
883
+ description='Return previous terminated container logs. Default: false. Useful to get logs for pods that are restarting.',
884
+ ),
881
885
  ) -> PodLogsResponse:
882
886
  """Get logs from a pod in a Kubernetes cluster.
883
887
 
@@ -905,6 +909,7 @@ class K8sHandler:
905
909
  since_seconds: Only return logs newer than this many seconds (optional)
906
910
  tail_lines: Number of lines to return from the end of the logs (defaults to 100)
907
911
  limit_bytes: Maximum number of bytes to return (defaults to 10KB)
912
+ previous: Return previous terminated container logs (defaults to false)
908
913
 
909
914
  Returns:
910
915
  PodLogsResponse with pod logs
@@ -934,6 +939,7 @@ class K8sHandler:
934
939
  since_seconds=since_seconds,
935
940
  tail_lines=tail_lines,
936
941
  limit_bytes=limit_bytes,
942
+ previous=previous,
937
943
  )
938
944
 
939
945
  # Split logs into lines
@@ -287,3 +287,81 @@ class MetricsGuidanceResponse(CallToolResult):
287
287
  ..., description='Resource type (cluster, node, pod, namespace, service)'
288
288
  )
289
289
  metrics: List[Dict[str, Any]] = Field(..., description='List of metrics with their details')
290
+
291
+
292
+ class EksVpcConfigResponse(CallToolResult):
293
+ """Response model for get_eks_vpc_config tool.
294
+
295
+ This model contains comprehensive VPC configuration details for any EKS cluster,
296
+ including CIDR blocks and route tables which are essential for understanding
297
+ network connectivity. For hybrid node setups, it also automatically identifies
298
+ and includes remote node and pod CIDR configurations.
299
+ """
300
+
301
+ vpc_id: str = Field(..., description='ID of the VPC')
302
+ cidr_block: str = Field(..., description='Primary CIDR block of the VPC')
303
+ additional_cidr_blocks: List[str] = Field(
304
+ [], description='Additional CIDR blocks associated with the VPC'
305
+ )
306
+ routes: List[Dict[str, Any]] = Field(
307
+ ..., description='List of route entries in the main route table'
308
+ )
309
+ remote_node_cidr_blocks: List[str] = Field(
310
+ [], description='CIDR blocks configured for remote node access (for hybrid setups)'
311
+ )
312
+ remote_pod_cidr_blocks: List[str] = Field(
313
+ [], description='CIDR blocks configured for remote pod access (for hybrid setups)'
314
+ )
315
+ subnets: List[Dict[str, Any]] = Field(
316
+ [], description='List of subnets in the VPC with their configurations'
317
+ )
318
+ cluster_name: str = Field(..., description='Name of the EKS cluster')
319
+
320
+
321
+ class EksInsightStatus(BaseModel):
322
+ """Status of an EKS insight with status code and reason."""
323
+
324
+ status: str = Field(..., description='Status of the insight (e.g., PASSING, FAILING, UNKNOWN)')
325
+ reason: str = Field(..., description='Explanation of the current status')
326
+
327
+
328
+ class EksInsightItem(BaseModel):
329
+ """Model for a single EKS insight item."""
330
+
331
+ id: str = Field(..., description='Unique identifier of the insight')
332
+ name: str = Field(..., description='Name of the insight')
333
+ category: str = Field(
334
+ ..., description='Category of the insight (e.g., CONFIGURATION, UPGRADE_READINESS)'
335
+ )
336
+ kubernetes_version: Optional[str] = Field(
337
+ None, description='Target Kubernetes version for upgrade insights'
338
+ )
339
+ last_refresh_time: float = Field(
340
+ ..., description='Timestamp when the insight was last refreshed'
341
+ )
342
+ last_transition_time: float = Field(
343
+ ..., description='Timestamp when the insight last changed status'
344
+ )
345
+ description: str = Field(..., description='Description of what the insight checks')
346
+ insight_status: EksInsightStatus = Field(..., description='Current status of the insight')
347
+ recommendation: Optional[str] = Field(
348
+ None, description='Recommendation for addressing the insight'
349
+ )
350
+ additional_info: Optional[Dict[str, str]] = Field(
351
+ None, description='Additional information links'
352
+ )
353
+ resources: Optional[List[str]] = Field(None, description='Resources involved in the insight')
354
+ category_specific_summary: Optional[Dict[str, Any]] = Field(
355
+ None, description='Additional category-specific details'
356
+ )
357
+
358
+
359
+ class EksInsightsResponse(CallToolResult):
360
+ """Response model for get_eks_insights tool."""
361
+
362
+ cluster_name: str = Field(..., description='Name of the EKS cluster')
363
+ insights: List[EksInsightItem] = Field(..., description='List of insights')
364
+ next_token: Optional[str] = Field(None, description='Token for pagination')
365
+ detail_mode: bool = Field(
366
+ False, description='Whether the response contains detailed insight information'
367
+ )
@@ -29,7 +29,9 @@ from awslabs.eks_mcp_server.cloudwatch_metrics_guidance_handler import CloudWatc
29
29
  from awslabs.eks_mcp_server.eks_kb_handler import EKSKnowledgeBaseHandler
30
30
  from awslabs.eks_mcp_server.eks_stack_handler import EksStackHandler
31
31
  from awslabs.eks_mcp_server.iam_handler import IAMHandler
32
+ from awslabs.eks_mcp_server.insights_handler import InsightsHandler
32
33
  from awslabs.eks_mcp_server.k8s_handler import K8sHandler
34
+ from awslabs.eks_mcp_server.vpc_config_handler import VpcConfigHandler
33
35
  from loguru import logger
34
36
  from mcp.server.fastmcp import FastMCP
35
37
 
@@ -149,6 +151,8 @@ def main():
149
151
  K8sHandler(mcp, allow_write, allow_sensitive_data_access)
150
152
  IAMHandler(mcp, allow_write)
151
153
  CloudWatchMetricsHandler(mcp)
154
+ VpcConfigHandler(mcp, allow_sensitive_data_access)
155
+ InsightsHandler(mcp, allow_sensitive_data_access)
152
156
 
153
157
  # Run server
154
158
  mcp.run()