awslabs.eks-mcp-server 0.1.16__py3-none-any.whl → 0.1.17__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/eks_mcp_server/__init__.py +1 -1
- awslabs/eks_mcp_server/cloudwatch_handler.py +42 -54
- awslabs/eks_mcp_server/cloudwatch_metrics_guidance_handler.py +15 -10
- awslabs/eks_mcp_server/eks_kb_handler.py +22 -4
- awslabs/eks_mcp_server/eks_stack_handler.py +97 -122
- awslabs/eks_mcp_server/iam_handler.py +36 -36
- awslabs/eks_mcp_server/insights_handler.py +29 -32
- awslabs/eks_mcp_server/k8s_handler.py +125 -145
- awslabs/eks_mcp_server/models.py +52 -62
- awslabs/eks_mcp_server/vpc_config_handler.py +18 -35
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/METADATA +2 -2
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/RECORD +16 -16
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/WHEEL +1 -1
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/entry_points.txt +0 -0
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/licenses/LICENSE +0 -0
- {awslabs_eks_mcp_server-0.1.16.dist-info → awslabs_eks_mcp_server-0.1.17.dist-info}/licenses/NOTICE +0 -0
|
@@ -14,25 +14,26 @@
|
|
|
14
14
|
|
|
15
15
|
"""Kubernetes handler for the EKS MCP Server."""
|
|
16
16
|
|
|
17
|
+
import json
|
|
17
18
|
import os
|
|
18
19
|
import yaml
|
|
19
20
|
from awslabs.eks_mcp_server.k8s_apis import K8sApis
|
|
20
21
|
from awslabs.eks_mcp_server.k8s_client_cache import K8sClientCache
|
|
21
22
|
from awslabs.eks_mcp_server.logging_helper import LogLevel, log_with_request_id
|
|
22
23
|
from awslabs.eks_mcp_server.models import (
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
ApiVersionsData,
|
|
25
|
+
ApplyYamlData,
|
|
25
26
|
EventItem,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
EventsData,
|
|
28
|
+
GenerateAppManifestData,
|
|
29
|
+
KubernetesResourceData,
|
|
30
|
+
KubernetesResourceListData,
|
|
30
31
|
Operation,
|
|
31
|
-
|
|
32
|
+
PodLogsData,
|
|
32
33
|
ResourceSummary,
|
|
33
34
|
)
|
|
34
35
|
from mcp.server.fastmcp import Context
|
|
35
|
-
from mcp.types import TextContent
|
|
36
|
+
from mcp.types import CallToolResult, TextContent
|
|
36
37
|
from pydantic import Field
|
|
37
38
|
from typing import Any, Dict, Optional
|
|
38
39
|
|
|
@@ -106,7 +107,7 @@ class K8sHandler:
|
|
|
106
107
|
True,
|
|
107
108
|
description='Whether to update resources if they already exist (similar to kubectl apply). Set to false to only create new resources.',
|
|
108
109
|
),
|
|
109
|
-
) ->
|
|
110
|
+
) -> CallToolResult:
|
|
110
111
|
"""Apply a Kubernetes YAML from a local file.
|
|
111
112
|
|
|
112
113
|
This tool applies Kubernetes resources defined in a YAML file to an EKS cluster,
|
|
@@ -141,12 +142,9 @@ class K8sHandler:
|
|
|
141
142
|
if not os.path.isabs(yaml_path):
|
|
142
143
|
error_msg = f'Path must be absolute: {yaml_path}'
|
|
143
144
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
144
|
-
return
|
|
145
|
+
return CallToolResult(
|
|
145
146
|
isError=True,
|
|
146
147
|
content=[TextContent(type='text', text=error_msg)],
|
|
147
|
-
force_applied=force,
|
|
148
|
-
resources_created=0,
|
|
149
|
-
resources_updated=0,
|
|
150
148
|
)
|
|
151
149
|
|
|
152
150
|
# Get Kubernetes client for the cluster
|
|
@@ -161,22 +159,16 @@ class K8sHandler:
|
|
|
161
159
|
except FileNotFoundError:
|
|
162
160
|
error_msg = f'YAML file not found: {yaml_path}'
|
|
163
161
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
164
|
-
return
|
|
162
|
+
return CallToolResult(
|
|
165
163
|
isError=True,
|
|
166
164
|
content=[TextContent(type='text', text=error_msg)],
|
|
167
|
-
force_applied=force,
|
|
168
|
-
resources_created=0,
|
|
169
|
-
resources_updated=0,
|
|
170
165
|
)
|
|
171
166
|
except IOError as e:
|
|
172
167
|
error_msg = f'Error reading YAML file {yaml_path}: {str(e)}'
|
|
173
168
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
174
|
-
return
|
|
169
|
+
return CallToolResult(
|
|
175
170
|
isError=True,
|
|
176
171
|
content=[TextContent(type='text', text=error_msg)],
|
|
177
|
-
force_applied=force,
|
|
178
|
-
resources_created=0,
|
|
179
|
-
resources_updated=0,
|
|
180
172
|
)
|
|
181
173
|
|
|
182
174
|
# Parse YAML documents
|
|
@@ -203,37 +195,37 @@ class K8sHandler:
|
|
|
203
195
|
)
|
|
204
196
|
log_with_request_id(ctx, LogLevel.INFO, success_msg)
|
|
205
197
|
|
|
206
|
-
|
|
207
|
-
isError=False,
|
|
208
|
-
content=[TextContent(type='text', text=success_msg)],
|
|
198
|
+
data = ApplyYamlData(
|
|
209
199
|
force_applied=force,
|
|
210
200
|
resources_created=created_count,
|
|
211
201
|
resources_updated=updated_count,
|
|
212
202
|
)
|
|
213
203
|
|
|
204
|
+
return CallToolResult(
|
|
205
|
+
isError=False,
|
|
206
|
+
content=[
|
|
207
|
+
TextContent(type='text', text=success_msg),
|
|
208
|
+
TextContent(type='text', text=json.dumps(data.model_dump())),
|
|
209
|
+
],
|
|
210
|
+
)
|
|
211
|
+
|
|
214
212
|
except Exception as e:
|
|
215
213
|
# Any exception means the operation failed
|
|
216
214
|
error_msg = f'Failed to apply YAML from file {yaml_path}: {str(e)}'
|
|
217
215
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
218
216
|
|
|
219
|
-
return
|
|
217
|
+
return CallToolResult(
|
|
220
218
|
isError=True,
|
|
221
219
|
content=[TextContent(type='text', text=error_msg)],
|
|
222
|
-
force_applied=force,
|
|
223
|
-
resources_created=0,
|
|
224
|
-
resources_updated=0,
|
|
225
220
|
)
|
|
226
221
|
|
|
227
222
|
except Exception as e:
|
|
228
223
|
error_msg = f'Error applying YAML from file: {str(e)}'
|
|
229
224
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
230
225
|
|
|
231
|
-
return
|
|
226
|
+
return CallToolResult(
|
|
232
227
|
isError=True,
|
|
233
228
|
content=[TextContent(type='text', text=error_msg)],
|
|
234
|
-
force_applied=force,
|
|
235
|
-
resources_created=0,
|
|
236
|
-
resources_updated=0,
|
|
237
229
|
)
|
|
238
230
|
|
|
239
231
|
def filter_null_values(self, data: Any) -> Any:
|
|
@@ -330,7 +322,7 @@ class K8sHandler:
|
|
|
330
322
|
For create and replace, this should be a complete resource definition.
|
|
331
323
|
For patch, this should contain only the fields to update.""",
|
|
332
324
|
),
|
|
333
|
-
) ->
|
|
325
|
+
) -> CallToolResult:
|
|
334
326
|
"""Manage a single Kubernetes resource with various operations.
|
|
335
327
|
|
|
336
328
|
This tool provides complete CRUD (Create, Read, Update, Delete) operations
|
|
@@ -381,30 +373,18 @@ class K8sHandler:
|
|
|
381
373
|
valid_ops = ', '.join([op.value for op in Operation])
|
|
382
374
|
error_msg = f'Invalid operation: {operation}. Valid operations are: {valid_ops}'
|
|
383
375
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
384
|
-
return
|
|
376
|
+
return CallToolResult(
|
|
385
377
|
isError=True,
|
|
386
378
|
content=[TextContent(type='text', text=error_msg)],
|
|
387
|
-
kind=kind,
|
|
388
|
-
name=name or '',
|
|
389
|
-
namespace=namespace,
|
|
390
|
-
api_version=api_version,
|
|
391
|
-
operation=operation,
|
|
392
|
-
resource=None,
|
|
393
379
|
)
|
|
394
380
|
|
|
395
381
|
# Check if write access is disabled and trying to perform a mutating operation
|
|
396
382
|
if not self.allow_write and operation_enum not in [Operation.READ]:
|
|
397
383
|
error_msg = f'Operation {operation} is not allowed without write access'
|
|
398
384
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
399
|
-
return
|
|
385
|
+
return CallToolResult(
|
|
400
386
|
isError=True,
|
|
401
387
|
content=[TextContent(type='text', text=error_msg)],
|
|
402
|
-
kind=kind,
|
|
403
|
-
name=name or '',
|
|
404
|
-
namespace=namespace,
|
|
405
|
-
api_version=api_version,
|
|
406
|
-
operation=operation,
|
|
407
|
-
resource=None,
|
|
408
388
|
)
|
|
409
389
|
|
|
410
390
|
# Check if sensitive data access is disabled and trying to read Secret resources
|
|
@@ -417,15 +397,9 @@ class K8sHandler:
|
|
|
417
397
|
'Access to Kubernetes Secrets requires --allow-sensitive-data-access flag'
|
|
418
398
|
)
|
|
419
399
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
420
|
-
return
|
|
400
|
+
return CallToolResult(
|
|
421
401
|
isError=True,
|
|
422
402
|
content=[TextContent(type='text', text=error_msg)],
|
|
423
|
-
kind=kind,
|
|
424
|
-
name=name or '',
|
|
425
|
-
namespace=namespace,
|
|
426
|
-
api_version=api_version,
|
|
427
|
-
operation=operation,
|
|
428
|
-
resource=None,
|
|
429
403
|
)
|
|
430
404
|
|
|
431
405
|
# Get Kubernetes client for the cluster
|
|
@@ -467,15 +441,8 @@ class K8sHandler:
|
|
|
467
441
|
f'Cleaned up resource response for {kind} {resource_name}',
|
|
468
442
|
)
|
|
469
443
|
|
|
470
|
-
# Return success response
|
|
471
|
-
|
|
472
|
-
isError=False,
|
|
473
|
-
content=[
|
|
474
|
-
TextContent(
|
|
475
|
-
type='text',
|
|
476
|
-
text=f'Successfully {operation_past_tense} {kind} {resource_name}',
|
|
477
|
-
)
|
|
478
|
-
],
|
|
444
|
+
# Return success response with structured data
|
|
445
|
+
data = KubernetesResourceData(
|
|
479
446
|
kind=kind,
|
|
480
447
|
name=name or '',
|
|
481
448
|
namespace=namespace,
|
|
@@ -484,6 +451,20 @@ class K8sHandler:
|
|
|
484
451
|
resource=resource_data,
|
|
485
452
|
)
|
|
486
453
|
|
|
454
|
+
return CallToolResult(
|
|
455
|
+
isError=False,
|
|
456
|
+
content=[
|
|
457
|
+
TextContent(
|
|
458
|
+
type='text',
|
|
459
|
+
text=f'Successfully {operation_past_tense} {kind} {resource_name}',
|
|
460
|
+
),
|
|
461
|
+
TextContent(
|
|
462
|
+
type='text',
|
|
463
|
+
text=json.dumps(data.model_dump()),
|
|
464
|
+
),
|
|
465
|
+
],
|
|
466
|
+
)
|
|
467
|
+
|
|
487
468
|
except Exception as e:
|
|
488
469
|
# Log error
|
|
489
470
|
resource_name = f'{namespace + "/" if namespace else ""}{name or ""}'
|
|
@@ -491,15 +472,9 @@ class K8sHandler:
|
|
|
491
472
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
492
473
|
|
|
493
474
|
# Return error response
|
|
494
|
-
return
|
|
475
|
+
return CallToolResult(
|
|
495
476
|
isError=True,
|
|
496
477
|
content=[TextContent(type='text', text=error_msg)],
|
|
497
|
-
kind=kind,
|
|
498
|
-
name=name or '',
|
|
499
|
-
namespace=namespace,
|
|
500
|
-
api_version=api_version,
|
|
501
|
-
operation=operation,
|
|
502
|
-
resource=None,
|
|
503
478
|
)
|
|
504
479
|
|
|
505
480
|
async def list_k8s_resources(
|
|
@@ -533,7 +508,7 @@ class K8sHandler:
|
|
|
533
508
|
description="""Field selector to filter resources (e.g., 'metadata.name=my-pod,status.phase=Running').
|
|
534
509
|
Uses the same syntax as kubectl's --field-selector flag.""",
|
|
535
510
|
),
|
|
536
|
-
) ->
|
|
511
|
+
) -> CallToolResult:
|
|
537
512
|
"""List Kubernetes resources of a specific kind.
|
|
538
513
|
|
|
539
514
|
This tool lists Kubernetes resources of a specified kind in an EKS cluster,
|
|
@@ -609,20 +584,27 @@ class K8sHandler:
|
|
|
609
584
|
ctx, LogLevel.INFO, f'Listed {len(summaries)} {kind} resources {resource_location}'
|
|
610
585
|
)
|
|
611
586
|
|
|
612
|
-
# Return success response
|
|
613
|
-
|
|
587
|
+
# Return success response with structured data
|
|
588
|
+
data = KubernetesResourceListData(
|
|
589
|
+
kind=kind,
|
|
590
|
+
api_version=api_version,
|
|
591
|
+
namespace=namespace,
|
|
592
|
+
count=len(summaries),
|
|
593
|
+
items=summaries,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
return CallToolResult(
|
|
614
597
|
isError=False,
|
|
615
598
|
content=[
|
|
616
599
|
TextContent(
|
|
617
600
|
type='text',
|
|
618
601
|
text=f'Successfully listed {len(summaries)} {kind} resources {resource_location}',
|
|
619
|
-
)
|
|
602
|
+
),
|
|
603
|
+
TextContent(
|
|
604
|
+
type='text',
|
|
605
|
+
text=json.dumps(data.model_dump()),
|
|
606
|
+
),
|
|
620
607
|
],
|
|
621
|
-
kind=kind,
|
|
622
|
-
api_version=api_version,
|
|
623
|
-
namespace=namespace,
|
|
624
|
-
count=len(summaries),
|
|
625
|
-
items=summaries,
|
|
626
608
|
)
|
|
627
609
|
|
|
628
610
|
except Exception as e:
|
|
@@ -631,14 +613,9 @@ class K8sHandler:
|
|
|
631
613
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
632
614
|
|
|
633
615
|
# Return error response
|
|
634
|
-
return
|
|
616
|
+
return CallToolResult(
|
|
635
617
|
isError=True,
|
|
636
618
|
content=[TextContent(type='text', text=error_msg)],
|
|
637
|
-
kind=kind,
|
|
638
|
-
api_version=api_version,
|
|
639
|
-
namespace=namespace,
|
|
640
|
-
count=0,
|
|
641
|
-
items=[],
|
|
642
619
|
)
|
|
643
620
|
|
|
644
621
|
async def generate_app_manifest(
|
|
@@ -674,7 +651,7 @@ class K8sHandler:
|
|
|
674
651
|
'internal',
|
|
675
652
|
description='AWS load balancer scheme. Options: "internal" (private VPC only) or "internet-facing" (public access).',
|
|
676
653
|
),
|
|
677
|
-
) ->
|
|
654
|
+
) -> CallToolResult:
|
|
678
655
|
"""Generate Kubernetes manifest for a deployment and service.
|
|
679
656
|
|
|
680
657
|
This tool generates Kubernetes manifests for deploying an application to an EKS cluster,
|
|
@@ -715,20 +692,18 @@ class K8sHandler:
|
|
|
715
692
|
if not self.allow_write:
|
|
716
693
|
error_msg = 'Operation generate_app_manifest is not allowed without write access'
|
|
717
694
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
718
|
-
return
|
|
695
|
+
return CallToolResult(
|
|
719
696
|
isError=True,
|
|
720
697
|
content=[TextContent(type='text', text=error_msg)],
|
|
721
|
-
output_file_path='',
|
|
722
698
|
)
|
|
723
699
|
|
|
724
700
|
# Validate that the path is absolute
|
|
725
701
|
if not os.path.isabs(output_dir):
|
|
726
702
|
error_msg = f'Output directory path must be absolute: {output_dir}'
|
|
727
703
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
728
|
-
return
|
|
704
|
+
return CallToolResult(
|
|
729
705
|
isError=True,
|
|
730
706
|
content=[TextContent(type='text', text=error_msg)],
|
|
731
|
-
output_file_path='',
|
|
732
707
|
)
|
|
733
708
|
|
|
734
709
|
log_with_request_id(
|
|
@@ -774,20 +749,25 @@ class K8sHandler:
|
|
|
774
749
|
|
|
775
750
|
log_with_request_id(ctx, LogLevel.INFO, success_message)
|
|
776
751
|
|
|
777
|
-
|
|
778
|
-
isError=False,
|
|
779
|
-
content=[TextContent(type='text', text=success_message)],
|
|
752
|
+
data = GenerateAppManifestData(
|
|
780
753
|
output_file_path=output_file_path,
|
|
781
754
|
)
|
|
782
755
|
|
|
756
|
+
return CallToolResult(
|
|
757
|
+
isError=False,
|
|
758
|
+
content=[
|
|
759
|
+
TextContent(type='text', text=success_message),
|
|
760
|
+
TextContent(type='text', text=json.dumps(data.model_dump())),
|
|
761
|
+
],
|
|
762
|
+
)
|
|
763
|
+
|
|
783
764
|
except Exception as e:
|
|
784
765
|
error_message = f'Failed to generate YAML: {str(e)}'
|
|
785
766
|
log_with_request_id(ctx, LogLevel.ERROR, error_message)
|
|
786
767
|
|
|
787
|
-
return
|
|
768
|
+
return CallToolResult(
|
|
788
769
|
isError=True,
|
|
789
770
|
content=[TextContent(type='text', text=error_message)],
|
|
790
|
-
output_file_path='',
|
|
791
771
|
)
|
|
792
772
|
|
|
793
773
|
def _remove_checkov_skip_annotations(self, content: str) -> str:
|
|
@@ -882,7 +862,7 @@ class K8sHandler:
|
|
|
882
862
|
False,
|
|
883
863
|
description='Return previous terminated container logs. Default: false. Useful to get logs for pods that are restarting.',
|
|
884
864
|
),
|
|
885
|
-
) ->
|
|
865
|
+
) -> CallToolResult:
|
|
886
866
|
"""Get logs from a pod in a Kubernetes cluster.
|
|
887
867
|
|
|
888
868
|
This tool retrieves logs from a specified pod in an EKS cluster, with options
|
|
@@ -918,13 +898,9 @@ class K8sHandler:
|
|
|
918
898
|
if not self.allow_sensitive_data_access:
|
|
919
899
|
error_msg = 'Access to pod logs requires --allow-sensitive-data-access flag'
|
|
920
900
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
921
|
-
return
|
|
901
|
+
return CallToolResult(
|
|
922
902
|
isError=True,
|
|
923
903
|
content=[TextContent(type='text', text=error_msg)],
|
|
924
|
-
pod_name=pod_name,
|
|
925
|
-
namespace=namespace,
|
|
926
|
-
container_name=container_name,
|
|
927
|
-
log_lines=[],
|
|
928
904
|
)
|
|
929
905
|
|
|
930
906
|
try:
|
|
@@ -959,19 +935,26 @@ class K8sHandler:
|
|
|
959
935
|
f'Retrieved {len(log_lines)} log lines from pod {namespace}/{pod_name}{container_info}',
|
|
960
936
|
)
|
|
961
937
|
|
|
962
|
-
# Return success response
|
|
963
|
-
|
|
938
|
+
# Return success response with structured data
|
|
939
|
+
data = PodLogsData(
|
|
940
|
+
pod_name=pod_name,
|
|
941
|
+
namespace=namespace,
|
|
942
|
+
container_name=container_name,
|
|
943
|
+
log_lines=log_lines,
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
return CallToolResult(
|
|
964
947
|
isError=False,
|
|
965
948
|
content=[
|
|
966
949
|
TextContent(
|
|
967
950
|
type='text',
|
|
968
951
|
text=f'Successfully retrieved {len(log_lines)} log lines from pod {namespace}/{pod_name}{container_info}',
|
|
969
|
-
)
|
|
952
|
+
),
|
|
953
|
+
TextContent(
|
|
954
|
+
type='text',
|
|
955
|
+
text=json.dumps(data.model_dump()),
|
|
956
|
+
),
|
|
970
957
|
],
|
|
971
|
-
pod_name=pod_name,
|
|
972
|
-
namespace=namespace,
|
|
973
|
-
container_name=container_name,
|
|
974
|
-
log_lines=log_lines,
|
|
975
958
|
)
|
|
976
959
|
|
|
977
960
|
except Exception as e:
|
|
@@ -985,13 +968,9 @@ class K8sHandler:
|
|
|
985
968
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
986
969
|
|
|
987
970
|
# Return error response
|
|
988
|
-
return
|
|
971
|
+
return CallToolResult(
|
|
989
972
|
isError=True,
|
|
990
973
|
content=[TextContent(type='text', text=error_msg)],
|
|
991
|
-
pod_name=pod_name,
|
|
992
|
-
namespace=namespace,
|
|
993
|
-
container_name=container_name,
|
|
994
|
-
log_lines=[],
|
|
995
974
|
)
|
|
996
975
|
|
|
997
976
|
async def get_k8s_events(
|
|
@@ -1010,7 +989,7 @@ class K8sHandler:
|
|
|
1010
989
|
description="""Namespace of the involved object. Required for namespaced resources (like Pods, Deployments).
|
|
1011
990
|
Not required for cluster-scoped resources (like Nodes, PersistentVolumes).""",
|
|
1012
991
|
),
|
|
1013
|
-
) ->
|
|
992
|
+
) -> CallToolResult:
|
|
1014
993
|
"""Get events related to a specific Kubernetes resource.
|
|
1015
994
|
|
|
1016
995
|
This tool retrieves Kubernetes events related to a specific resource, providing
|
|
@@ -1048,14 +1027,9 @@ class K8sHandler:
|
|
|
1048
1027
|
if not self.allow_sensitive_data_access:
|
|
1049
1028
|
error_msg = 'Access to Kubernetes events requires --allow-sensitive-data-access flag'
|
|
1050
1029
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
1051
|
-
return
|
|
1030
|
+
return CallToolResult(
|
|
1052
1031
|
isError=True,
|
|
1053
1032
|
content=[TextContent(type='text', text=error_msg)],
|
|
1054
|
-
involved_object_kind=kind,
|
|
1055
|
-
involved_object_name=name,
|
|
1056
|
-
involved_object_namespace=namespace,
|
|
1057
|
-
count=0,
|
|
1058
|
-
events=[],
|
|
1059
1033
|
)
|
|
1060
1034
|
|
|
1061
1035
|
try:
|
|
@@ -1096,20 +1070,27 @@ class K8sHandler:
|
|
|
1096
1070
|
ctx, LogLevel.INFO, f'Retrieved {len(events)} events for {kind} {resource_name}'
|
|
1097
1071
|
)
|
|
1098
1072
|
|
|
1099
|
-
# Return success response
|
|
1100
|
-
|
|
1073
|
+
# Return success response with structured data
|
|
1074
|
+
data = EventsData(
|
|
1075
|
+
involved_object_kind=kind,
|
|
1076
|
+
involved_object_name=name,
|
|
1077
|
+
involved_object_namespace=namespace,
|
|
1078
|
+
count=len(events),
|
|
1079
|
+
events=event_items,
|
|
1080
|
+
)
|
|
1081
|
+
|
|
1082
|
+
return CallToolResult(
|
|
1101
1083
|
isError=False,
|
|
1102
1084
|
content=[
|
|
1103
1085
|
TextContent(
|
|
1104
1086
|
type='text',
|
|
1105
1087
|
text=f'Successfully retrieved {len(events)} events for {kind} {resource_name}',
|
|
1106
|
-
)
|
|
1088
|
+
),
|
|
1089
|
+
TextContent(
|
|
1090
|
+
type='text',
|
|
1091
|
+
text=json.dumps(data.model_dump()),
|
|
1092
|
+
),
|
|
1107
1093
|
],
|
|
1108
|
-
involved_object_kind=kind,
|
|
1109
|
-
involved_object_name=name,
|
|
1110
|
-
involved_object_namespace=namespace,
|
|
1111
|
-
count=len(events),
|
|
1112
|
-
events=event_items,
|
|
1113
1094
|
)
|
|
1114
1095
|
|
|
1115
1096
|
except Exception as e:
|
|
@@ -1121,14 +1102,9 @@ class K8sHandler:
|
|
|
1121
1102
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
1122
1103
|
|
|
1123
1104
|
# Return error response
|
|
1124
|
-
return
|
|
1105
|
+
return CallToolResult(
|
|
1125
1106
|
isError=True,
|
|
1126
1107
|
content=[TextContent(type='text', text=error_msg)],
|
|
1127
|
-
involved_object_kind=kind,
|
|
1128
|
-
involved_object_name=name or '',
|
|
1129
|
-
involved_object_namespace=namespace,
|
|
1130
|
-
count=0,
|
|
1131
|
-
events=[],
|
|
1132
1108
|
)
|
|
1133
1109
|
|
|
1134
1110
|
async def list_api_versions(
|
|
@@ -1137,7 +1113,7 @@ class K8sHandler:
|
|
|
1137
1113
|
cluster_name: str = Field(
|
|
1138
1114
|
..., description='Name of the EKS cluster to query for available API versions.'
|
|
1139
1115
|
),
|
|
1140
|
-
) ->
|
|
1116
|
+
) -> CallToolResult:
|
|
1141
1117
|
"""List all available API versions in the Kubernetes cluster.
|
|
1142
1118
|
|
|
1143
1119
|
This tool discovers all available API versions on the Kubernetes cluster,
|
|
@@ -1177,18 +1153,25 @@ class K8sHandler:
|
|
|
1177
1153
|
f'Retrieved {len(api_versions)} API versions from cluster {cluster_name}',
|
|
1178
1154
|
)
|
|
1179
1155
|
|
|
1180
|
-
# Return success response
|
|
1181
|
-
|
|
1156
|
+
# Return success response with structured data
|
|
1157
|
+
data = ApiVersionsData(
|
|
1158
|
+
cluster_name=cluster_name,
|
|
1159
|
+
api_versions=api_versions,
|
|
1160
|
+
count=len(api_versions),
|
|
1161
|
+
)
|
|
1162
|
+
|
|
1163
|
+
return CallToolResult(
|
|
1182
1164
|
isError=False,
|
|
1183
1165
|
content=[
|
|
1184
1166
|
TextContent(
|
|
1185
1167
|
type='text',
|
|
1186
1168
|
text=f'Successfully retrieved {len(api_versions)} API versions from cluster {cluster_name}',
|
|
1187
|
-
)
|
|
1169
|
+
),
|
|
1170
|
+
TextContent(
|
|
1171
|
+
type='text',
|
|
1172
|
+
text=json.dumps(data.model_dump()),
|
|
1173
|
+
),
|
|
1188
1174
|
],
|
|
1189
|
-
cluster_name=cluster_name,
|
|
1190
|
-
api_versions=api_versions,
|
|
1191
|
-
count=len(api_versions),
|
|
1192
1175
|
)
|
|
1193
1176
|
|
|
1194
1177
|
except Exception as e:
|
|
@@ -1197,10 +1180,7 @@ class K8sHandler:
|
|
|
1197
1180
|
log_with_request_id(ctx, LogLevel.ERROR, error_msg)
|
|
1198
1181
|
|
|
1199
1182
|
# Return error response
|
|
1200
|
-
return
|
|
1183
|
+
return CallToolResult(
|
|
1201
1184
|
isError=True,
|
|
1202
1185
|
content=[TextContent(type='text', text=error_msg)],
|
|
1203
|
-
cluster_name=cluster_name,
|
|
1204
|
-
api_versions=[],
|
|
1205
|
-
count=0,
|
|
1206
1186
|
)
|