kubectl-mcp-server 1.14.0__py3-none-any.whl → 1.16.0__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.
- kubectl_mcp_server-1.16.0.dist-info/METADATA +1047 -0
- kubectl_mcp_server-1.16.0.dist-info/RECORD +61 -0
- kubectl_mcp_tool/__init__.py +1 -1
- kubectl_mcp_tool/crd_detector.py +247 -0
- kubectl_mcp_tool/k8s_config.py +304 -63
- kubectl_mcp_tool/mcp_server.py +27 -0
- kubectl_mcp_tool/tools/__init__.py +20 -0
- kubectl_mcp_tool/tools/backup.py +881 -0
- kubectl_mcp_tool/tools/capi.py +727 -0
- kubectl_mcp_tool/tools/certs.py +709 -0
- kubectl_mcp_tool/tools/cilium.py +582 -0
- kubectl_mcp_tool/tools/cluster.py +395 -121
- kubectl_mcp_tool/tools/core.py +157 -60
- kubectl_mcp_tool/tools/cost.py +97 -41
- kubectl_mcp_tool/tools/deployments.py +173 -56
- kubectl_mcp_tool/tools/diagnostics.py +40 -13
- kubectl_mcp_tool/tools/gitops.py +552 -0
- kubectl_mcp_tool/tools/helm.py +133 -46
- kubectl_mcp_tool/tools/keda.py +464 -0
- kubectl_mcp_tool/tools/kiali.py +652 -0
- kubectl_mcp_tool/tools/kubevirt.py +803 -0
- kubectl_mcp_tool/tools/networking.py +106 -32
- kubectl_mcp_tool/tools/operations.py +176 -50
- kubectl_mcp_tool/tools/pods.py +162 -50
- kubectl_mcp_tool/tools/policy.py +554 -0
- kubectl_mcp_tool/tools/rollouts.py +790 -0
- kubectl_mcp_tool/tools/security.py +89 -36
- kubectl_mcp_tool/tools/storage.py +35 -16
- tests/test_browser.py +2 -2
- tests/test_ecosystem.py +331 -0
- tests/test_tools.py +73 -10
- kubectl_mcp_server-1.14.0.dist-info/METADATA +0 -780
- kubectl_mcp_server-1.14.0.dist-info/RECORD +0 -49
- {kubectl_mcp_server-1.14.0.dist-info → kubectl_mcp_server-1.16.0.dist-info}/WHEEL +0 -0
- {kubectl_mcp_server-1.14.0.dist-info → kubectl_mcp_server-1.16.0.dist-info}/entry_points.txt +0 -0
- {kubectl_mcp_server-1.14.0.dist-info → kubectl_mcp_server-1.16.0.dist-info}/licenses/LICENSE +0 -0
- {kubectl_mcp_server-1.14.0.dist-info → kubectl_mcp_server-1.16.0.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import subprocess
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from mcp.types import ToolAnnotations
|
|
6
6
|
|
|
7
|
+
from ..k8s_config import (
|
|
8
|
+
get_apps_client,
|
|
9
|
+
get_batch_client,
|
|
10
|
+
get_autoscaling_client,
|
|
11
|
+
get_policy_client,
|
|
12
|
+
_load_config_for_context,
|
|
13
|
+
)
|
|
14
|
+
|
|
7
15
|
logger = logging.getLogger("mcp-server")
|
|
8
16
|
|
|
9
17
|
|
|
18
|
+
def _get_kubectl_context_args(context: str) -> List[str]:
|
|
19
|
+
"""Get kubectl context arguments if context is specified."""
|
|
20
|
+
if context:
|
|
21
|
+
return ["--context", context]
|
|
22
|
+
return []
|
|
23
|
+
|
|
24
|
+
|
|
10
25
|
def register_deployment_tools(server, non_destructive: bool):
|
|
11
26
|
"""Register deployment and workload management tools."""
|
|
12
27
|
|
|
@@ -16,12 +31,18 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
16
31
|
readOnlyHint=True,
|
|
17
32
|
),
|
|
18
33
|
)
|
|
19
|
-
def get_deployments(
|
|
20
|
-
|
|
34
|
+
def get_deployments(
|
|
35
|
+
namespace: Optional[str] = None,
|
|
36
|
+
context: str = ""
|
|
37
|
+
) -> Dict[str, Any]:
|
|
38
|
+
"""Get all deployments in the specified namespace.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
namespace: Namespace to list deployments from (all namespaces if not specified)
|
|
42
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
43
|
+
"""
|
|
21
44
|
try:
|
|
22
|
-
|
|
23
|
-
config.load_kube_config()
|
|
24
|
-
apps = client.AppsV1Api()
|
|
45
|
+
apps = get_apps_client(context)
|
|
25
46
|
|
|
26
47
|
if namespace:
|
|
27
48
|
deployments = apps.list_namespaced_deployment(namespace)
|
|
@@ -30,6 +51,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
30
51
|
|
|
31
52
|
return {
|
|
32
53
|
"success": True,
|
|
54
|
+
"context": context or "current",
|
|
33
55
|
"deployments": [
|
|
34
56
|
{
|
|
35
57
|
"name": d.metadata.name,
|
|
@@ -51,14 +73,28 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
51
73
|
destructiveHint=True,
|
|
52
74
|
),
|
|
53
75
|
)
|
|
54
|
-
def create_deployment(
|
|
55
|
-
|
|
76
|
+
def create_deployment(
|
|
77
|
+
name: str,
|
|
78
|
+
image: str,
|
|
79
|
+
replicas: int,
|
|
80
|
+
namespace: Optional[str] = "default",
|
|
81
|
+
context: str = ""
|
|
82
|
+
) -> Dict[str, Any]:
|
|
83
|
+
"""Create a new deployment.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
name: Name of the deployment
|
|
87
|
+
image: Container image to deploy
|
|
88
|
+
replicas: Number of replicas
|
|
89
|
+
namespace: Namespace to create deployment in (default: "default")
|
|
90
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
91
|
+
"""
|
|
56
92
|
if non_destructive:
|
|
57
93
|
return {"success": False, "error": "Blocked: non-destructive mode"}
|
|
58
94
|
try:
|
|
59
|
-
from kubernetes import client
|
|
60
|
-
|
|
61
|
-
apps =
|
|
95
|
+
from kubernetes import client
|
|
96
|
+
|
|
97
|
+
apps = get_apps_client(context)
|
|
62
98
|
|
|
63
99
|
deployment = client.V1Deployment(
|
|
64
100
|
metadata=client.V1ObjectMeta(name=name),
|
|
@@ -82,7 +118,11 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
82
118
|
)
|
|
83
119
|
|
|
84
120
|
apps.create_namespaced_deployment(namespace, deployment)
|
|
85
|
-
return {
|
|
121
|
+
return {
|
|
122
|
+
"success": True,
|
|
123
|
+
"context": context or "current",
|
|
124
|
+
"message": f"Deployment {name} created"
|
|
125
|
+
}
|
|
86
126
|
except Exception as e:
|
|
87
127
|
logger.error(f"Error creating deployment: {e}")
|
|
88
128
|
return {"success": False, "error": str(e)}
|
|
@@ -93,17 +133,33 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
93
133
|
destructiveHint=True,
|
|
94
134
|
),
|
|
95
135
|
)
|
|
96
|
-
def scale_deployment(
|
|
97
|
-
|
|
136
|
+
def scale_deployment(
|
|
137
|
+
name: str,
|
|
138
|
+
replicas: int,
|
|
139
|
+
namespace: Optional[str] = "default",
|
|
140
|
+
context: str = ""
|
|
141
|
+
) -> Dict[str, Any]:
|
|
142
|
+
"""Scale a deployment to a specified number of replicas.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
name: Name of the deployment
|
|
146
|
+
replicas: Target number of replicas
|
|
147
|
+
namespace: Namespace of the deployment (default: "default")
|
|
148
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
149
|
+
"""
|
|
98
150
|
if non_destructive:
|
|
99
151
|
return {"success": False, "error": "Blocked: non-destructive mode"}
|
|
100
152
|
try:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
153
|
+
cmd = ["kubectl", "scale", "deployment", name, f"--replicas={replicas}", "-n", namespace]
|
|
154
|
+
cmd.extend(_get_kubectl_context_args(context))
|
|
155
|
+
|
|
156
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
105
157
|
if result.returncode == 0:
|
|
106
|
-
return {
|
|
158
|
+
return {
|
|
159
|
+
"success": True,
|
|
160
|
+
"context": context or "current",
|
|
161
|
+
"message": f"Deployment {name} scaled to {replicas} replicas"
|
|
162
|
+
}
|
|
107
163
|
return {"success": False, "error": result.stderr}
|
|
108
164
|
except Exception as e:
|
|
109
165
|
logger.error(f"Error scaling deployment: {e}")
|
|
@@ -115,17 +171,31 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
115
171
|
destructiveHint=True,
|
|
116
172
|
),
|
|
117
173
|
)
|
|
118
|
-
def restart_deployment(
|
|
119
|
-
|
|
174
|
+
def restart_deployment(
|
|
175
|
+
name: str,
|
|
176
|
+
namespace: str = "default",
|
|
177
|
+
context: str = ""
|
|
178
|
+
) -> Dict[str, Any]:
|
|
179
|
+
"""Restart a deployment by triggering a rolling update.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
name: Name of the deployment
|
|
183
|
+
namespace: Namespace of the deployment (default: "default")
|
|
184
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
185
|
+
"""
|
|
120
186
|
if non_destructive:
|
|
121
187
|
return {"success": False, "error": "Blocked: non-destructive mode"}
|
|
122
188
|
try:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
)
|
|
189
|
+
cmd = ["kubectl", "rollout", "restart", "deployment", name, "-n", namespace]
|
|
190
|
+
cmd.extend(_get_kubectl_context_args(context))
|
|
191
|
+
|
|
192
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
127
193
|
if result.returncode == 0:
|
|
128
|
-
return {
|
|
194
|
+
return {
|
|
195
|
+
"success": True,
|
|
196
|
+
"context": context or "current",
|
|
197
|
+
"message": f"Deployment {name} restarted"
|
|
198
|
+
}
|
|
129
199
|
return {"success": False, "error": result.stderr}
|
|
130
200
|
except Exception as e:
|
|
131
201
|
logger.error(f"Error restarting deployment: {e}")
|
|
@@ -137,12 +207,18 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
137
207
|
readOnlyHint=True,
|
|
138
208
|
),
|
|
139
209
|
)
|
|
140
|
-
def get_replicasets(
|
|
141
|
-
|
|
210
|
+
def get_replicasets(
|
|
211
|
+
namespace: Optional[str] = None,
|
|
212
|
+
context: str = ""
|
|
213
|
+
) -> Dict[str, Any]:
|
|
214
|
+
"""Get ReplicaSets in a namespace or cluster-wide.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
namespace: Namespace to list ReplicaSets from (all namespaces if not specified)
|
|
218
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
219
|
+
"""
|
|
142
220
|
try:
|
|
143
|
-
|
|
144
|
-
config.load_kube_config()
|
|
145
|
-
apps = client.AppsV1Api()
|
|
221
|
+
apps = get_apps_client(context)
|
|
146
222
|
|
|
147
223
|
if namespace:
|
|
148
224
|
rs_list = apps.list_namespaced_replica_set(namespace)
|
|
@@ -151,6 +227,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
151
227
|
|
|
152
228
|
return {
|
|
153
229
|
"success": True,
|
|
230
|
+
"context": context or "current",
|
|
154
231
|
"replicaSets": [
|
|
155
232
|
{
|
|
156
233
|
"name": rs.metadata.name,
|
|
@@ -176,12 +253,18 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
176
253
|
readOnlyHint=True,
|
|
177
254
|
),
|
|
178
255
|
)
|
|
179
|
-
def get_statefulsets(
|
|
180
|
-
|
|
256
|
+
def get_statefulsets(
|
|
257
|
+
namespace: Optional[str] = None,
|
|
258
|
+
context: str = ""
|
|
259
|
+
) -> Dict[str, Any]:
|
|
260
|
+
"""Get StatefulSets in a namespace or cluster-wide.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
namespace: Namespace to list StatefulSets from (all namespaces if not specified)
|
|
264
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
265
|
+
"""
|
|
181
266
|
try:
|
|
182
|
-
|
|
183
|
-
config.load_kube_config()
|
|
184
|
-
apps = client.AppsV1Api()
|
|
267
|
+
apps = get_apps_client(context)
|
|
185
268
|
|
|
186
269
|
if namespace:
|
|
187
270
|
sts_list = apps.list_namespaced_stateful_set(namespace)
|
|
@@ -190,6 +273,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
190
273
|
|
|
191
274
|
return {
|
|
192
275
|
"success": True,
|
|
276
|
+
"context": context or "current",
|
|
193
277
|
"statefulSets": [
|
|
194
278
|
{
|
|
195
279
|
"name": sts.metadata.name,
|
|
@@ -213,12 +297,18 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
213
297
|
readOnlyHint=True,
|
|
214
298
|
),
|
|
215
299
|
)
|
|
216
|
-
def get_daemonsets(
|
|
217
|
-
|
|
300
|
+
def get_daemonsets(
|
|
301
|
+
namespace: Optional[str] = None,
|
|
302
|
+
context: str = ""
|
|
303
|
+
) -> Dict[str, Any]:
|
|
304
|
+
"""Get DaemonSets in a namespace or cluster-wide.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
namespace: Namespace to list DaemonSets from (all namespaces if not specified)
|
|
308
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
309
|
+
"""
|
|
218
310
|
try:
|
|
219
|
-
|
|
220
|
-
config.load_kube_config()
|
|
221
|
-
apps = client.AppsV1Api()
|
|
311
|
+
apps = get_apps_client(context)
|
|
222
312
|
|
|
223
313
|
if namespace:
|
|
224
314
|
ds_list = apps.list_namespaced_daemon_set(namespace)
|
|
@@ -227,6 +317,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
227
317
|
|
|
228
318
|
return {
|
|
229
319
|
"success": True,
|
|
320
|
+
"context": context or "current",
|
|
230
321
|
"daemonSets": [
|
|
231
322
|
{
|
|
232
323
|
"name": ds.metadata.name,
|
|
@@ -250,12 +341,20 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
250
341
|
readOnlyHint=True,
|
|
251
342
|
),
|
|
252
343
|
)
|
|
253
|
-
def get_jobs(
|
|
254
|
-
|
|
344
|
+
def get_jobs(
|
|
345
|
+
namespace: Optional[str] = None,
|
|
346
|
+
include_cronjobs: bool = True,
|
|
347
|
+
context: str = ""
|
|
348
|
+
) -> Dict[str, Any]:
|
|
349
|
+
"""Get Jobs and optionally CronJobs.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
namespace: Namespace to list Jobs from (all namespaces if not specified)
|
|
353
|
+
include_cronjobs: Whether to include CronJobs in the result
|
|
354
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
355
|
+
"""
|
|
255
356
|
try:
|
|
256
|
-
|
|
257
|
-
config.load_kube_config()
|
|
258
|
-
batch = client.BatchV1Api()
|
|
357
|
+
batch = get_batch_client(context)
|
|
259
358
|
|
|
260
359
|
if namespace:
|
|
261
360
|
jobs = batch.list_namespaced_job(namespace)
|
|
@@ -264,6 +363,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
264
363
|
|
|
265
364
|
result = {
|
|
266
365
|
"success": True,
|
|
366
|
+
"context": context or "current",
|
|
267
367
|
"jobs": [
|
|
268
368
|
{
|
|
269
369
|
"name": job.metadata.name,
|
|
@@ -308,12 +408,21 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
308
408
|
readOnlyHint=True,
|
|
309
409
|
),
|
|
310
410
|
)
|
|
311
|
-
def get_hpa(
|
|
312
|
-
|
|
411
|
+
def get_hpa(
|
|
412
|
+
namespace: Optional[str] = None,
|
|
413
|
+
context: str = ""
|
|
414
|
+
) -> Dict[str, Any]:
|
|
415
|
+
"""Get HorizontalPodAutoscalers in a namespace or cluster-wide.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
namespace: Namespace to list HPAs from (all namespaces if not specified)
|
|
419
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
420
|
+
"""
|
|
313
421
|
try:
|
|
314
|
-
from kubernetes import client
|
|
315
|
-
|
|
316
|
-
|
|
422
|
+
from kubernetes import client
|
|
423
|
+
|
|
424
|
+
api_client = _load_config_for_context(context)
|
|
425
|
+
autoscaling = client.AutoscalingV2Api(api_client=api_client)
|
|
317
426
|
|
|
318
427
|
if namespace:
|
|
319
428
|
hpas = autoscaling.list_namespaced_horizontal_pod_autoscaler(namespace)
|
|
@@ -322,6 +431,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
322
431
|
|
|
323
432
|
return {
|
|
324
433
|
"success": True,
|
|
434
|
+
"context": context or "current",
|
|
325
435
|
"hpas": [
|
|
326
436
|
{
|
|
327
437
|
"name": hpa.metadata.name,
|
|
@@ -348,12 +458,18 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
348
458
|
readOnlyHint=True,
|
|
349
459
|
),
|
|
350
460
|
)
|
|
351
|
-
def get_pdb(
|
|
352
|
-
|
|
461
|
+
def get_pdb(
|
|
462
|
+
namespace: Optional[str] = None,
|
|
463
|
+
context: str = ""
|
|
464
|
+
) -> Dict[str, Any]:
|
|
465
|
+
"""Get PodDisruptionBudgets in a namespace or cluster-wide.
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
namespace: Namespace to list PDBs from (all namespaces if not specified)
|
|
469
|
+
context: Kubernetes context to use (uses current context if not specified)
|
|
470
|
+
"""
|
|
353
471
|
try:
|
|
354
|
-
|
|
355
|
-
config.load_kube_config()
|
|
356
|
-
policy = client.PolicyV1Api()
|
|
472
|
+
policy = get_policy_client(context)
|
|
357
473
|
|
|
358
474
|
if namespace:
|
|
359
475
|
pdbs = policy.list_namespaced_pod_disruption_budget(namespace)
|
|
@@ -362,6 +478,7 @@ def register_deployment_tools(server, non_destructive: bool):
|
|
|
362
478
|
|
|
363
479
|
return {
|
|
364
480
|
"success": True,
|
|
481
|
+
"context": context or "current",
|
|
365
482
|
"pdbs": [
|
|
366
483
|
{
|
|
367
484
|
"name": pdb.metadata.name,
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import subprocess
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from mcp.types import ToolAnnotations
|
|
6
6
|
|
|
7
|
+
from ..k8s_config import get_k8s_client, get_apps_client
|
|
8
|
+
|
|
7
9
|
logger = logging.getLogger("mcp-server")
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
def _get_kubectl_context_args(context: str) -> List[str]:
|
|
13
|
+
"""Get kubectl context arguments if context is specified."""
|
|
14
|
+
if context:
|
|
15
|
+
return ["--context", context]
|
|
16
|
+
return []
|
|
17
|
+
|
|
18
|
+
|
|
10
19
|
def register_diagnostics_tools(server, non_destructive: bool):
|
|
11
20
|
"""Register diagnostic and troubleshooting tools.
|
|
12
21
|
|
|
@@ -21,13 +30,18 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
21
30
|
readOnlyHint=True,
|
|
22
31
|
),
|
|
23
32
|
)
|
|
24
|
-
def compare_namespaces(namespace1: str, namespace2: str, resource_type: str = "deployment") -> Dict[str, Any]:
|
|
25
|
-
"""Compare resources between two namespaces.
|
|
33
|
+
def compare_namespaces(namespace1: str, namespace2: str, resource_type: str = "deployment", context: str = "") -> Dict[str, Any]:
|
|
34
|
+
"""Compare resources between two namespaces.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
namespace1: First namespace to compare
|
|
38
|
+
namespace2: Second namespace to compare
|
|
39
|
+
resource_type: Type of resource to compare (deployment, service, configmap, secret)
|
|
40
|
+
context: Kubernetes context to use (optional, uses current context if not specified)
|
|
41
|
+
"""
|
|
26
42
|
try:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
apps = client.AppsV1Api()
|
|
30
|
-
v1 = client.CoreV1Api()
|
|
43
|
+
apps = get_apps_client(context)
|
|
44
|
+
v1 = get_k8s_client(context)
|
|
31
45
|
|
|
32
46
|
def get_resources(ns, res_type):
|
|
33
47
|
if res_type == "deployment":
|
|
@@ -63,6 +77,7 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
63
77
|
|
|
64
78
|
return {
|
|
65
79
|
"success": True,
|
|
80
|
+
"context": context or "current",
|
|
66
81
|
"resourceType": resource_type,
|
|
67
82
|
"namespaces": [namespace1, namespace2],
|
|
68
83
|
"summary": {
|
|
@@ -85,10 +100,16 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
85
100
|
readOnlyHint=True,
|
|
86
101
|
),
|
|
87
102
|
)
|
|
88
|
-
def get_pod_metrics(namespace: Optional[str] = None, pod_name: Optional[str] = None) -> Dict[str, Any]:
|
|
89
|
-
"""Get pod resource usage metrics (requires metrics-server).
|
|
103
|
+
def get_pod_metrics(namespace: Optional[str] = None, pod_name: Optional[str] = None, context: str = "") -> Dict[str, Any]:
|
|
104
|
+
"""Get pod resource usage metrics (requires metrics-server).
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
namespace: Target namespace (optional, all namespaces if not specified)
|
|
108
|
+
pod_name: Filter by specific pod name (optional)
|
|
109
|
+
context: Kubernetes context to use (optional, uses current context if not specified)
|
|
110
|
+
"""
|
|
90
111
|
try:
|
|
91
|
-
cmd = ["kubectl"
|
|
112
|
+
cmd = ["kubectl"] + _get_kubectl_context_args(context) + ["top", "pods", "--no-headers"]
|
|
92
113
|
if namespace:
|
|
93
114
|
cmd.extend(["-n", namespace])
|
|
94
115
|
else:
|
|
@@ -124,6 +145,7 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
124
145
|
|
|
125
146
|
return {
|
|
126
147
|
"success": True,
|
|
148
|
+
"context": context or "current",
|
|
127
149
|
"count": len(metrics),
|
|
128
150
|
"metrics": metrics
|
|
129
151
|
}
|
|
@@ -139,10 +161,14 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
139
161
|
readOnlyHint=True,
|
|
140
162
|
),
|
|
141
163
|
)
|
|
142
|
-
def get_node_metrics() -> Dict[str, Any]:
|
|
143
|
-
"""Get node resource usage metrics (requires metrics-server).
|
|
164
|
+
def get_node_metrics(context: str = "") -> Dict[str, Any]:
|
|
165
|
+
"""Get node resource usage metrics (requires metrics-server).
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
context: Kubernetes context to use (optional, uses current context if not specified)
|
|
169
|
+
"""
|
|
144
170
|
try:
|
|
145
|
-
cmd = ["kubectl"
|
|
171
|
+
cmd = ["kubectl"] + _get_kubectl_context_args(context) + ["top", "nodes", "--no-headers"]
|
|
146
172
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
147
173
|
|
|
148
174
|
if result.returncode != 0:
|
|
@@ -164,6 +190,7 @@ def register_diagnostics_tools(server, non_destructive: bool):
|
|
|
164
190
|
|
|
165
191
|
return {
|
|
166
192
|
"success": True,
|
|
193
|
+
"context": context or "current",
|
|
167
194
|
"count": len(metrics),
|
|
168
195
|
"metrics": metrics
|
|
169
196
|
}
|