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
kubectl_mcp_tool/k8s_config.py
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
Kubernetes configuration loader utility.
|
|
3
3
|
|
|
4
4
|
Handles both in-cluster and out-of-cluster (kubeconfig) configurations.
|
|
5
|
+
Supports multi-cluster operations with context targeting.
|
|
5
6
|
|
|
6
|
-
This module
|
|
7
|
-
|
|
7
|
+
This module provides context-aware client creation for multi-cluster support.
|
|
8
|
+
All get_*_client() functions accept an optional 'context' parameter.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
import os
|
|
11
12
|
import logging
|
|
13
|
+
from typing import Optional, Any
|
|
12
14
|
|
|
13
15
|
logger = logging.getLogger("mcp-server")
|
|
14
16
|
|
|
@@ -16,20 +18,20 @@ _config_loaded = False
|
|
|
16
18
|
_original_load_kube_config = None
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
def load_kubernetes_config():
|
|
21
|
+
def load_kubernetes_config(context: str = ""):
|
|
20
22
|
"""Load Kubernetes configuration.
|
|
21
23
|
|
|
22
24
|
Tries in-cluster config first (when running inside a pod),
|
|
23
25
|
then falls back to kubeconfig file.
|
|
24
26
|
|
|
27
|
+
Args:
|
|
28
|
+
context: Optional context name for kubeconfig provider
|
|
29
|
+
|
|
25
30
|
Returns:
|
|
26
31
|
bool: True if config loaded successfully, False otherwise
|
|
27
32
|
"""
|
|
28
33
|
global _config_loaded
|
|
29
34
|
|
|
30
|
-
if _config_loaded:
|
|
31
|
-
return True
|
|
32
|
-
|
|
33
35
|
from kubernetes import config
|
|
34
36
|
from kubernetes.config.config_exception import ConfigException
|
|
35
37
|
|
|
@@ -46,8 +48,14 @@ def load_kubernetes_config():
|
|
|
46
48
|
try:
|
|
47
49
|
kubeconfig_path = os.environ.get('KUBECONFIG', '~/.kube/config')
|
|
48
50
|
kubeconfig_path = os.path.expanduser(kubeconfig_path)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
|
|
52
|
+
if context:
|
|
53
|
+
config.load_kube_config(config_file=kubeconfig_path, context=context)
|
|
54
|
+
logger.info(f"Loaded kubeconfig context '{context}' from {kubeconfig_path}")
|
|
55
|
+
else:
|
|
56
|
+
config.load_kube_config(config_file=kubeconfig_path)
|
|
57
|
+
logger.info(f"Loaded kubeconfig from {kubeconfig_path}")
|
|
58
|
+
|
|
51
59
|
_config_loaded = True
|
|
52
60
|
return True
|
|
53
61
|
except ConfigException as e:
|
|
@@ -102,8 +110,52 @@ def patch_kubernetes_config():
|
|
|
102
110
|
patch_kubernetes_config()
|
|
103
111
|
|
|
104
112
|
|
|
105
|
-
def
|
|
106
|
-
"""
|
|
113
|
+
def _load_config_for_context(context: str = "") -> Any:
|
|
114
|
+
"""
|
|
115
|
+
Load kubernetes config for a specific context and return ApiClient.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
context: Context name (empty for default)
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
kubernetes.client.ApiClient configured for the context
|
|
122
|
+
"""
|
|
123
|
+
from kubernetes import client, config
|
|
124
|
+
from kubernetes.config.config_exception import ConfigException
|
|
125
|
+
|
|
126
|
+
# Try in-cluster first
|
|
127
|
+
try:
|
|
128
|
+
config.load_incluster_config()
|
|
129
|
+
return client.ApiClient()
|
|
130
|
+
except ConfigException:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
# Load kubeconfig with optional context
|
|
134
|
+
kubeconfig_path = os.environ.get('KUBECONFIG', '~/.kube/config')
|
|
135
|
+
kubeconfig_path = os.path.expanduser(kubeconfig_path)
|
|
136
|
+
|
|
137
|
+
api_config = client.Configuration()
|
|
138
|
+
|
|
139
|
+
if context:
|
|
140
|
+
config.load_kube_config(
|
|
141
|
+
config_file=kubeconfig_path,
|
|
142
|
+
context=context,
|
|
143
|
+
client_configuration=api_config
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
config.load_kube_config(
|
|
147
|
+
config_file=kubeconfig_path,
|
|
148
|
+
client_configuration=api_config
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return client.ApiClient(configuration=api_config)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def get_k8s_client(context: str = ""):
|
|
155
|
+
"""Get a configured Kubernetes Core API client.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
context: Optional context name for multi-cluster support
|
|
107
159
|
|
|
108
160
|
Returns:
|
|
109
161
|
kubernetes.client.CoreV1Api: Configured Kubernetes client
|
|
@@ -113,15 +165,19 @@ def get_k8s_client():
|
|
|
113
165
|
"""
|
|
114
166
|
from kubernetes import client
|
|
115
167
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
168
|
+
try:
|
|
169
|
+
api_client = _load_config_for_context(context)
|
|
170
|
+
return client.CoreV1Api(api_client=api_client)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
120
173
|
|
|
121
174
|
|
|
122
|
-
def get_apps_client():
|
|
175
|
+
def get_apps_client(context: str = ""):
|
|
123
176
|
"""Get a configured Kubernetes Apps API client.
|
|
124
177
|
|
|
178
|
+
Args:
|
|
179
|
+
context: Optional context name for multi-cluster support
|
|
180
|
+
|
|
125
181
|
Returns:
|
|
126
182
|
kubernetes.client.AppsV1Api: Configured Apps API client
|
|
127
183
|
|
|
@@ -130,15 +186,19 @@ def get_apps_client():
|
|
|
130
186
|
"""
|
|
131
187
|
from kubernetes import client
|
|
132
188
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
189
|
+
try:
|
|
190
|
+
api_client = _load_config_for_context(context)
|
|
191
|
+
return client.AppsV1Api(api_client=api_client)
|
|
192
|
+
except Exception as e:
|
|
193
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
137
194
|
|
|
138
195
|
|
|
139
|
-
def get_rbac_client():
|
|
196
|
+
def get_rbac_client(context: str = ""):
|
|
140
197
|
"""Get a configured Kubernetes RBAC API client.
|
|
141
198
|
|
|
199
|
+
Args:
|
|
200
|
+
context: Optional context name for multi-cluster support
|
|
201
|
+
|
|
142
202
|
Returns:
|
|
143
203
|
kubernetes.client.RbacAuthorizationV1Api: Configured RBAC client
|
|
144
204
|
|
|
@@ -147,15 +207,19 @@ def get_rbac_client():
|
|
|
147
207
|
"""
|
|
148
208
|
from kubernetes import client
|
|
149
209
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
210
|
+
try:
|
|
211
|
+
api_client = _load_config_for_context(context)
|
|
212
|
+
return client.RbacAuthorizationV1Api(api_client=api_client)
|
|
213
|
+
except Exception as e:
|
|
214
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
154
215
|
|
|
155
216
|
|
|
156
|
-
def get_networking_client():
|
|
217
|
+
def get_networking_client(context: str = ""):
|
|
157
218
|
"""Get a configured Kubernetes Networking API client.
|
|
158
219
|
|
|
220
|
+
Args:
|
|
221
|
+
context: Optional context name for multi-cluster support
|
|
222
|
+
|
|
159
223
|
Returns:
|
|
160
224
|
kubernetes.client.NetworkingV1Api: Configured Networking client
|
|
161
225
|
|
|
@@ -164,15 +228,19 @@ def get_networking_client():
|
|
|
164
228
|
"""
|
|
165
229
|
from kubernetes import client
|
|
166
230
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
231
|
+
try:
|
|
232
|
+
api_client = _load_config_for_context(context)
|
|
233
|
+
return client.NetworkingV1Api(api_client=api_client)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
171
236
|
|
|
172
237
|
|
|
173
|
-
def get_storage_client():
|
|
238
|
+
def get_storage_client(context: str = ""):
|
|
174
239
|
"""Get a configured Kubernetes Storage API client.
|
|
175
240
|
|
|
241
|
+
Args:
|
|
242
|
+
context: Optional context name for multi-cluster support
|
|
243
|
+
|
|
176
244
|
Returns:
|
|
177
245
|
kubernetes.client.StorageV1Api: Configured Storage client
|
|
178
246
|
|
|
@@ -181,15 +249,19 @@ def get_storage_client():
|
|
|
181
249
|
"""
|
|
182
250
|
from kubernetes import client
|
|
183
251
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
252
|
+
try:
|
|
253
|
+
api_client = _load_config_for_context(context)
|
|
254
|
+
return client.StorageV1Api(api_client=api_client)
|
|
255
|
+
except Exception as e:
|
|
256
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
188
257
|
|
|
189
258
|
|
|
190
|
-
def get_batch_client():
|
|
259
|
+
def get_batch_client(context: str = ""):
|
|
191
260
|
"""Get a configured Kubernetes Batch API client.
|
|
192
261
|
|
|
262
|
+
Args:
|
|
263
|
+
context: Optional context name for multi-cluster support
|
|
264
|
+
|
|
193
265
|
Returns:
|
|
194
266
|
kubernetes.client.BatchV1Api: Configured Batch client
|
|
195
267
|
|
|
@@ -198,15 +270,19 @@ def get_batch_client():
|
|
|
198
270
|
"""
|
|
199
271
|
from kubernetes import client
|
|
200
272
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
273
|
+
try:
|
|
274
|
+
api_client = _load_config_for_context(context)
|
|
275
|
+
return client.BatchV1Api(api_client=api_client)
|
|
276
|
+
except Exception as e:
|
|
277
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
205
278
|
|
|
206
279
|
|
|
207
|
-
def get_autoscaling_client():
|
|
280
|
+
def get_autoscaling_client(context: str = ""):
|
|
208
281
|
"""Get a configured Kubernetes Autoscaling API client.
|
|
209
282
|
|
|
283
|
+
Args:
|
|
284
|
+
context: Optional context name for multi-cluster support
|
|
285
|
+
|
|
210
286
|
Returns:
|
|
211
287
|
kubernetes.client.AutoscalingV1Api: Configured Autoscaling client
|
|
212
288
|
|
|
@@ -215,15 +291,19 @@ def get_autoscaling_client():
|
|
|
215
291
|
"""
|
|
216
292
|
from kubernetes import client
|
|
217
293
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
294
|
+
try:
|
|
295
|
+
api_client = _load_config_for_context(context)
|
|
296
|
+
return client.AutoscalingV1Api(api_client=api_client)
|
|
297
|
+
except Exception as e:
|
|
298
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
222
299
|
|
|
223
300
|
|
|
224
|
-
def get_policy_client():
|
|
301
|
+
def get_policy_client(context: str = ""):
|
|
225
302
|
"""Get a configured Kubernetes Policy API client.
|
|
226
303
|
|
|
304
|
+
Args:
|
|
305
|
+
context: Optional context name for multi-cluster support
|
|
306
|
+
|
|
227
307
|
Returns:
|
|
228
308
|
kubernetes.client.PolicyV1Api: Configured Policy client
|
|
229
309
|
|
|
@@ -232,15 +312,19 @@ def get_policy_client():
|
|
|
232
312
|
"""
|
|
233
313
|
from kubernetes import client
|
|
234
314
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
315
|
+
try:
|
|
316
|
+
api_client = _load_config_for_context(context)
|
|
317
|
+
return client.PolicyV1Api(api_client=api_client)
|
|
318
|
+
except Exception as e:
|
|
319
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
239
320
|
|
|
240
321
|
|
|
241
|
-
def get_custom_objects_client():
|
|
322
|
+
def get_custom_objects_client(context: str = ""):
|
|
242
323
|
"""Get a configured Kubernetes Custom Objects API client.
|
|
243
324
|
|
|
325
|
+
Args:
|
|
326
|
+
context: Optional context name for multi-cluster support
|
|
327
|
+
|
|
244
328
|
Returns:
|
|
245
329
|
kubernetes.client.CustomObjectsApi: Configured Custom Objects client
|
|
246
330
|
|
|
@@ -249,15 +333,19 @@ def get_custom_objects_client():
|
|
|
249
333
|
"""
|
|
250
334
|
from kubernetes import client
|
|
251
335
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
336
|
+
try:
|
|
337
|
+
api_client = _load_config_for_context(context)
|
|
338
|
+
return client.CustomObjectsApi(api_client=api_client)
|
|
339
|
+
except Exception as e:
|
|
340
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
256
341
|
|
|
257
342
|
|
|
258
|
-
def get_version_client():
|
|
343
|
+
def get_version_client(context: str = ""):
|
|
259
344
|
"""Get a configured Kubernetes Version API client.
|
|
260
345
|
|
|
346
|
+
Args:
|
|
347
|
+
context: Optional context name for multi-cluster support
|
|
348
|
+
|
|
261
349
|
Returns:
|
|
262
350
|
kubernetes.client.VersionApi: Configured Version client
|
|
263
351
|
|
|
@@ -266,15 +354,19 @@ def get_version_client():
|
|
|
266
354
|
"""
|
|
267
355
|
from kubernetes import client
|
|
268
356
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
357
|
+
try:
|
|
358
|
+
api_client = _load_config_for_context(context)
|
|
359
|
+
return client.VersionApi(api_client=api_client)
|
|
360
|
+
except Exception as e:
|
|
361
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
273
362
|
|
|
274
363
|
|
|
275
|
-
def get_admissionregistration_client():
|
|
364
|
+
def get_admissionregistration_client(context: str = ""):
|
|
276
365
|
"""Get a configured Kubernetes Admission Registration API client.
|
|
277
366
|
|
|
367
|
+
Args:
|
|
368
|
+
context: Optional context name for multi-cluster support
|
|
369
|
+
|
|
278
370
|
Returns:
|
|
279
371
|
kubernetes.client.AdmissionregistrationV1Api: Configured Admission client
|
|
280
372
|
|
|
@@ -283,7 +375,156 @@ def get_admissionregistration_client():
|
|
|
283
375
|
"""
|
|
284
376
|
from kubernetes import client
|
|
285
377
|
|
|
286
|
-
|
|
287
|
-
|
|
378
|
+
try:
|
|
379
|
+
api_client = _load_config_for_context(context)
|
|
380
|
+
return client.AdmissionregistrationV1Api(api_client=api_client)
|
|
381
|
+
except Exception as e:
|
|
382
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def get_apiextensions_client(context: str = ""):
|
|
386
|
+
"""Get a configured Kubernetes API Extensions client.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
context: Optional context name for multi-cluster support
|
|
288
390
|
|
|
289
|
-
|
|
391
|
+
Returns:
|
|
392
|
+
kubernetes.client.ApiextensionsV1Api: Configured API Extensions client
|
|
393
|
+
|
|
394
|
+
Raises:
|
|
395
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
396
|
+
"""
|
|
397
|
+
from kubernetes import client
|
|
398
|
+
|
|
399
|
+
try:
|
|
400
|
+
api_client = _load_config_for_context(context)
|
|
401
|
+
return client.ApiextensionsV1Api(api_client=api_client)
|
|
402
|
+
except Exception as e:
|
|
403
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def get_coordination_client(context: str = ""):
|
|
407
|
+
"""Get a configured Kubernetes Coordination API client.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
context: Optional context name for multi-cluster support
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
kubernetes.client.CoordinationV1Api: Configured Coordination client
|
|
414
|
+
|
|
415
|
+
Raises:
|
|
416
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
417
|
+
"""
|
|
418
|
+
from kubernetes import client
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
api_client = _load_config_for_context(context)
|
|
422
|
+
return client.CoordinationV1Api(api_client=api_client)
|
|
423
|
+
except Exception as e:
|
|
424
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def get_events_client(context: str = ""):
|
|
428
|
+
"""Get a configured Kubernetes Events API client.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
context: Optional context name for multi-cluster support
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
kubernetes.client.EventsV1Api: Configured Events client
|
|
435
|
+
|
|
436
|
+
Raises:
|
|
437
|
+
RuntimeError: If Kubernetes config cannot be loaded
|
|
438
|
+
"""
|
|
439
|
+
from kubernetes import client
|
|
440
|
+
|
|
441
|
+
try:
|
|
442
|
+
api_client = _load_config_for_context(context)
|
|
443
|
+
return client.EventsV1Api(api_client=api_client)
|
|
444
|
+
except Exception as e:
|
|
445
|
+
raise RuntimeError(f"Invalid kube-config. Context: {context or 'default'}. Error: {e}")
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
# Utility functions for context management
|
|
449
|
+
|
|
450
|
+
def list_contexts() -> list:
|
|
451
|
+
"""
|
|
452
|
+
List all available kubeconfig contexts.
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
List of context dictionaries with name, cluster, user, namespace
|
|
456
|
+
"""
|
|
457
|
+
from kubernetes import config
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
kubeconfig_path = os.environ.get('KUBECONFIG', '~/.kube/config')
|
|
461
|
+
kubeconfig_path = os.path.expanduser(kubeconfig_path)
|
|
462
|
+
|
|
463
|
+
contexts, active = config.list_kube_config_contexts(config_file=kubeconfig_path)
|
|
464
|
+
|
|
465
|
+
return [
|
|
466
|
+
{
|
|
467
|
+
"name": ctx.get("name"),
|
|
468
|
+
"cluster": ctx.get("context", {}).get("cluster"),
|
|
469
|
+
"user": ctx.get("context", {}).get("user"),
|
|
470
|
+
"namespace": ctx.get("context", {}).get("namespace", "default"),
|
|
471
|
+
"active": ctx.get("name") == (active.get("name") if active else None)
|
|
472
|
+
}
|
|
473
|
+
for ctx in contexts
|
|
474
|
+
]
|
|
475
|
+
except Exception as e:
|
|
476
|
+
logger.error(f"Error listing contexts: {e}")
|
|
477
|
+
return []
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def get_active_context() -> Optional[str]:
|
|
481
|
+
"""
|
|
482
|
+
Get the current active context name.
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
Active context name or None
|
|
486
|
+
"""
|
|
487
|
+
from kubernetes import config
|
|
488
|
+
|
|
489
|
+
try:
|
|
490
|
+
kubeconfig_path = os.environ.get('KUBECONFIG', '~/.kube/config')
|
|
491
|
+
kubeconfig_path = os.path.expanduser(kubeconfig_path)
|
|
492
|
+
|
|
493
|
+
_, active = config.list_kube_config_contexts(config_file=kubeconfig_path)
|
|
494
|
+
return active.get("name") if active else None
|
|
495
|
+
except Exception as e:
|
|
496
|
+
logger.error(f"Error getting active context: {e}")
|
|
497
|
+
return None
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def context_exists(context: str) -> bool:
|
|
501
|
+
"""
|
|
502
|
+
Check if a context exists in kubeconfig.
|
|
503
|
+
|
|
504
|
+
Args:
|
|
505
|
+
context: Context name to check
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
True if context exists
|
|
509
|
+
"""
|
|
510
|
+
contexts = list_contexts()
|
|
511
|
+
return any(ctx["name"] == context for ctx in contexts)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _get_kubectl_context_args(context: str = "") -> list:
|
|
515
|
+
"""
|
|
516
|
+
Get kubectl command arguments for specifying a context.
|
|
517
|
+
|
|
518
|
+
This utility function returns the appropriate --context flag arguments
|
|
519
|
+
for kubectl commands when targeting a specific cluster.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
context: Context name (empty string for default context)
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
List of command arguments, e.g., ["--context", "my-cluster"]
|
|
526
|
+
or empty list if no context specified
|
|
527
|
+
"""
|
|
528
|
+
if context and context.strip():
|
|
529
|
+
return ["--context", context.strip()]
|
|
530
|
+
return []
|
kubectl_mcp_tool/mcp_server.py
CHANGED
|
@@ -45,6 +45,16 @@ from kubectl_mcp_tool.tools import (
|
|
|
45
45
|
is_browser_available,
|
|
46
46
|
register_ui_tools,
|
|
47
47
|
is_ui_available,
|
|
48
|
+
register_gitops_tools,
|
|
49
|
+
register_certs_tools,
|
|
50
|
+
register_policy_tools,
|
|
51
|
+
register_backup_tools,
|
|
52
|
+
register_keda_tools,
|
|
53
|
+
register_cilium_tools,
|
|
54
|
+
register_rollouts_tools,
|
|
55
|
+
register_capi_tools,
|
|
56
|
+
register_kubevirt_tools,
|
|
57
|
+
register_istio_tools,
|
|
48
58
|
)
|
|
49
59
|
from kubectl_mcp_tool.resources import register_resources
|
|
50
60
|
from kubectl_mcp_tool.prompts import register_prompts
|
|
@@ -196,6 +206,23 @@ class MCPServer:
|
|
|
196
206
|
else:
|
|
197
207
|
logger.debug("MCP-UI tools disabled (install mcp-ui-server to enable)")
|
|
198
208
|
|
|
209
|
+
# Register ecosystem tools (GitOps, Cert-Manager, Policy, Backup)
|
|
210
|
+
# These tools auto-detect installed CRDs and gracefully handle missing components
|
|
211
|
+
register_gitops_tools(self.server, self.non_destructive)
|
|
212
|
+
register_certs_tools(self.server, self.non_destructive)
|
|
213
|
+
register_policy_tools(self.server, self.non_destructive)
|
|
214
|
+
register_backup_tools(self.server, self.non_destructive)
|
|
215
|
+
logger.debug("Ecosystem tools registered (GitOps, Certs, Policy, Backup)")
|
|
216
|
+
|
|
217
|
+
# Register advanced ecosystem tools (KEDA, Cilium, Rollouts, CAPI, KubeVirt, Istio)
|
|
218
|
+
register_keda_tools(self.server, self.non_destructive)
|
|
219
|
+
register_cilium_tools(self.server, self.non_destructive)
|
|
220
|
+
register_rollouts_tools(self.server, self.non_destructive)
|
|
221
|
+
register_capi_tools(self.server, self.non_destructive)
|
|
222
|
+
register_kubevirt_tools(self.server, self.non_destructive)
|
|
223
|
+
register_istio_tools(self.server, self.non_destructive)
|
|
224
|
+
logger.debug("Advanced ecosystem tools registered (KEDA, Cilium, Rollouts, CAPI, KubeVirt, Istio)")
|
|
225
|
+
|
|
199
226
|
def setup_resources(self):
|
|
200
227
|
"""Set up MCP resources for Kubernetes data exposure."""
|
|
201
228
|
register_resources(self.server)
|
|
@@ -11,6 +11,16 @@ from .diagnostics import register_diagnostics_tools
|
|
|
11
11
|
from .cost import register_cost_tools
|
|
12
12
|
from .browser import register_browser_tools, is_browser_available
|
|
13
13
|
from .ui import register_ui_tools, is_ui_available
|
|
14
|
+
from .gitops import register_gitops_tools
|
|
15
|
+
from .certs import register_certs_tools
|
|
16
|
+
from .policy import register_policy_tools
|
|
17
|
+
from .backup import register_backup_tools
|
|
18
|
+
from .keda import register_keda_tools
|
|
19
|
+
from .cilium import register_cilium_tools
|
|
20
|
+
from .rollouts import register_rollouts_tools
|
|
21
|
+
from .capi import register_capi_tools
|
|
22
|
+
from .kubevirt import register_kubevirt_tools
|
|
23
|
+
from .kiali import register_istio_tools
|
|
14
24
|
|
|
15
25
|
__all__ = [
|
|
16
26
|
"register_helm_tools",
|
|
@@ -28,4 +38,14 @@ __all__ = [
|
|
|
28
38
|
"is_browser_available",
|
|
29
39
|
"register_ui_tools",
|
|
30
40
|
"is_ui_available",
|
|
41
|
+
"register_gitops_tools",
|
|
42
|
+
"register_certs_tools",
|
|
43
|
+
"register_policy_tools",
|
|
44
|
+
"register_backup_tools",
|
|
45
|
+
"register_keda_tools",
|
|
46
|
+
"register_cilium_tools",
|
|
47
|
+
"register_rollouts_tools",
|
|
48
|
+
"register_capi_tools",
|
|
49
|
+
"register_kubevirt_tools",
|
|
50
|
+
"register_istio_tools",
|
|
31
51
|
]
|