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
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"""KEDA autoscaling toolset for kubectl-mcp-server.
|
|
2
|
+
|
|
3
|
+
Provides tools for managing KEDA ScaledObjects, ScaledJobs, and TriggerAuthentications.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import json
|
|
8
|
+
from typing import Dict, Any, List
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from fastmcp import FastMCP
|
|
12
|
+
from fastmcp.tools import ToolAnnotations
|
|
13
|
+
except ImportError:
|
|
14
|
+
from mcp.server.fastmcp import FastMCP
|
|
15
|
+
from mcp.types import ToolAnnotations
|
|
16
|
+
|
|
17
|
+
from ..k8s_config import _get_kubectl_context_args
|
|
18
|
+
from ..crd_detector import crd_exists
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
SCALEDOBJECT_CRD = "scaledobjects.keda.sh"
|
|
22
|
+
SCALEDJOB_CRD = "scaledjobs.keda.sh"
|
|
23
|
+
TRIGGERAUTH_CRD = "triggerauthentications.keda.sh"
|
|
24
|
+
CLUSTERTRIGGERAUTH_CRD = "clustertriggerauthentications.keda.sh"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _run_kubectl(args: List[str], context: str = "") -> Dict[str, Any]:
|
|
28
|
+
"""Run kubectl command and return result."""
|
|
29
|
+
cmd = ["kubectl"] + _get_kubectl_context_args(context) + args
|
|
30
|
+
try:
|
|
31
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
32
|
+
if result.returncode == 0:
|
|
33
|
+
return {"success": True, "output": result.stdout}
|
|
34
|
+
return {"success": False, "error": result.stderr}
|
|
35
|
+
except subprocess.TimeoutExpired:
|
|
36
|
+
return {"success": False, "error": "Command timed out"}
|
|
37
|
+
except Exception as e:
|
|
38
|
+
return {"success": False, "error": str(e)}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_resources(kind: str, namespace: str = "", context: str = "", label_selector: str = "") -> List[Dict]:
|
|
42
|
+
"""Get Kubernetes resources of a specific kind."""
|
|
43
|
+
args = ["get", kind, "-o", "json"]
|
|
44
|
+
if namespace:
|
|
45
|
+
args.extend(["-n", namespace])
|
|
46
|
+
else:
|
|
47
|
+
args.append("-A")
|
|
48
|
+
if label_selector:
|
|
49
|
+
args.extend(["-l", label_selector])
|
|
50
|
+
|
|
51
|
+
result = _run_kubectl(args, context)
|
|
52
|
+
if result["success"]:
|
|
53
|
+
try:
|
|
54
|
+
data = json.loads(result["output"])
|
|
55
|
+
return data.get("items", [])
|
|
56
|
+
except json.JSONDecodeError:
|
|
57
|
+
return []
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def keda_scaledobjects_list(
|
|
62
|
+
namespace: str = "",
|
|
63
|
+
context: str = "",
|
|
64
|
+
label_selector: str = ""
|
|
65
|
+
) -> Dict[str, Any]:
|
|
66
|
+
"""List KEDA ScaledObjects with their status.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
namespace: Filter by namespace (empty for all namespaces)
|
|
70
|
+
context: Kubernetes context to use (optional)
|
|
71
|
+
label_selector: Label selector to filter resources
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
List of ScaledObjects with their scaling status
|
|
75
|
+
"""
|
|
76
|
+
if not crd_exists(SCALEDOBJECT_CRD, context):
|
|
77
|
+
return {
|
|
78
|
+
"success": False,
|
|
79
|
+
"error": "KEDA is not installed (scaledobjects.keda.sh CRD not found)"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
objects = []
|
|
83
|
+
for item in _get_resources("scaledobjects.keda.sh", namespace, context, label_selector):
|
|
84
|
+
status = item.get("status", {})
|
|
85
|
+
spec = item.get("spec", {})
|
|
86
|
+
conditions = status.get("conditions", [])
|
|
87
|
+
|
|
88
|
+
ready_cond = next((c for c in conditions if c.get("type") == "Ready"), {})
|
|
89
|
+
active_cond = next((c for c in conditions if c.get("type") == "Active"), {})
|
|
90
|
+
|
|
91
|
+
triggers = spec.get("triggers", [])
|
|
92
|
+
trigger_types = [t.get("type", "unknown") for t in triggers]
|
|
93
|
+
|
|
94
|
+
objects.append({
|
|
95
|
+
"name": item["metadata"]["name"],
|
|
96
|
+
"namespace": item["metadata"]["namespace"],
|
|
97
|
+
"ready": ready_cond.get("status") == "True",
|
|
98
|
+
"active": active_cond.get("status") == "True",
|
|
99
|
+
"status": ready_cond.get("reason", "Unknown"),
|
|
100
|
+
"message": ready_cond.get("message", ""),
|
|
101
|
+
"scale_target_ref": spec.get("scaleTargetRef", {}),
|
|
102
|
+
"min_replicas": spec.get("minReplicaCount", 0),
|
|
103
|
+
"max_replicas": spec.get("maxReplicaCount", 100),
|
|
104
|
+
"current_replicas": status.get("scaleTargetKind", {}).get("replicas"),
|
|
105
|
+
"trigger_types": trigger_types,
|
|
106
|
+
"triggers_count": len(triggers),
|
|
107
|
+
"paused_replicas": spec.get("pausedReplicaCount"),
|
|
108
|
+
"cooldown_period": spec.get("cooldownPeriod", 300),
|
|
109
|
+
"polling_interval": spec.get("pollingInterval", 30),
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
active_count = sum(1 for o in objects if o["active"])
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
"context": context or "current",
|
|
116
|
+
"total": len(objects),
|
|
117
|
+
"active": active_count,
|
|
118
|
+
"scaledobjects": objects,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def keda_scaledobject_get(
|
|
123
|
+
name: str,
|
|
124
|
+
namespace: str,
|
|
125
|
+
context: str = ""
|
|
126
|
+
) -> Dict[str, Any]:
|
|
127
|
+
"""Get detailed information about a ScaledObject.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
name: Name of the ScaledObject
|
|
131
|
+
namespace: Namespace of the ScaledObject
|
|
132
|
+
context: Kubernetes context to use (optional)
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Detailed ScaledObject information
|
|
136
|
+
"""
|
|
137
|
+
if not crd_exists(SCALEDOBJECT_CRD, context):
|
|
138
|
+
return {"success": False, "error": "KEDA is not installed"}
|
|
139
|
+
|
|
140
|
+
args = ["get", "scaledobjects.keda.sh", name, "-n", namespace, "-o", "json"]
|
|
141
|
+
result = _run_kubectl(args, context)
|
|
142
|
+
|
|
143
|
+
if result["success"]:
|
|
144
|
+
try:
|
|
145
|
+
data = json.loads(result["output"])
|
|
146
|
+
return {
|
|
147
|
+
"success": True,
|
|
148
|
+
"context": context or "current",
|
|
149
|
+
"scaledobject": data,
|
|
150
|
+
}
|
|
151
|
+
except json.JSONDecodeError:
|
|
152
|
+
return {"success": False, "error": "Failed to parse response"}
|
|
153
|
+
|
|
154
|
+
return {"success": False, "error": result.get("error", "Unknown error")}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def keda_scaledjobs_list(
|
|
158
|
+
namespace: str = "",
|
|
159
|
+
context: str = "",
|
|
160
|
+
label_selector: str = ""
|
|
161
|
+
) -> Dict[str, Any]:
|
|
162
|
+
"""List KEDA ScaledJobs with their status.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
namespace: Filter by namespace (empty for all namespaces)
|
|
166
|
+
context: Kubernetes context to use (optional)
|
|
167
|
+
label_selector: Label selector to filter resources
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
List of ScaledJobs with their scaling status
|
|
171
|
+
"""
|
|
172
|
+
if not crd_exists(SCALEDJOB_CRD, context):
|
|
173
|
+
return {
|
|
174
|
+
"success": False,
|
|
175
|
+
"error": "KEDA ScaledJobs CRD not found"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
jobs = []
|
|
179
|
+
for item in _get_resources("scaledjobs.keda.sh", namespace, context, label_selector):
|
|
180
|
+
status = item.get("status", {})
|
|
181
|
+
spec = item.get("spec", {})
|
|
182
|
+
conditions = status.get("conditions", [])
|
|
183
|
+
|
|
184
|
+
ready_cond = next((c for c in conditions if c.get("type") == "Ready"), {})
|
|
185
|
+
|
|
186
|
+
triggers = spec.get("triggers", [])
|
|
187
|
+
trigger_types = [t.get("type", "unknown") for t in triggers]
|
|
188
|
+
|
|
189
|
+
jobs.append({
|
|
190
|
+
"name": item["metadata"]["name"],
|
|
191
|
+
"namespace": item["metadata"]["namespace"],
|
|
192
|
+
"ready": ready_cond.get("status") == "True",
|
|
193
|
+
"status": ready_cond.get("reason", "Unknown"),
|
|
194
|
+
"message": ready_cond.get("message", ""),
|
|
195
|
+
"job_target_ref": spec.get("jobTargetRef", {}),
|
|
196
|
+
"min_replicas": spec.get("minReplicaCount", 0),
|
|
197
|
+
"max_replicas": spec.get("maxReplicaCount", 100),
|
|
198
|
+
"trigger_types": trigger_types,
|
|
199
|
+
"triggers_count": len(triggers),
|
|
200
|
+
"polling_interval": spec.get("pollingInterval", 30),
|
|
201
|
+
"successful_jobs_history": spec.get("successfulJobsHistoryLimit", 100),
|
|
202
|
+
"failed_jobs_history": spec.get("failedJobsHistoryLimit", 100),
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"context": context or "current",
|
|
207
|
+
"total": len(jobs),
|
|
208
|
+
"scaledjobs": jobs,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def keda_triggerauths_list(
|
|
213
|
+
namespace: str = "",
|
|
214
|
+
context: str = "",
|
|
215
|
+
include_cluster: bool = True
|
|
216
|
+
) -> Dict[str, Any]:
|
|
217
|
+
"""List KEDA TriggerAuthentications and ClusterTriggerAuthentications.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
namespace: Filter by namespace (empty for all)
|
|
221
|
+
context: Kubernetes context to use (optional)
|
|
222
|
+
include_cluster: Include ClusterTriggerAuthentications
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
List of trigger authentications
|
|
226
|
+
"""
|
|
227
|
+
auths = []
|
|
228
|
+
|
|
229
|
+
if crd_exists(TRIGGERAUTH_CRD, context):
|
|
230
|
+
for item in _get_resources("triggerauthentications.keda.sh", namespace, context):
|
|
231
|
+
spec = item.get("spec", {})
|
|
232
|
+
secret_refs = spec.get("secretTargetRef", [])
|
|
233
|
+
env_refs = spec.get("env", [])
|
|
234
|
+
|
|
235
|
+
auths.append({
|
|
236
|
+
"name": item["metadata"]["name"],
|
|
237
|
+
"namespace": item["metadata"]["namespace"],
|
|
238
|
+
"kind": "TriggerAuthentication",
|
|
239
|
+
"secret_refs_count": len(secret_refs),
|
|
240
|
+
"env_refs_count": len(env_refs),
|
|
241
|
+
"has_pod_identity": "podIdentity" in spec,
|
|
242
|
+
"has_azure_identity": "azureKeyVault" in spec,
|
|
243
|
+
"has_hashicorp_vault": "hashiCorpVault" in spec,
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
if include_cluster and crd_exists(CLUSTERTRIGGERAUTH_CRD, context):
|
|
247
|
+
for item in _get_resources("clustertriggerauthentications.keda.sh", "", context):
|
|
248
|
+
spec = item.get("spec", {})
|
|
249
|
+
secret_refs = spec.get("secretTargetRef", [])
|
|
250
|
+
env_refs = spec.get("env", [])
|
|
251
|
+
|
|
252
|
+
auths.append({
|
|
253
|
+
"name": item["metadata"]["name"],
|
|
254
|
+
"namespace": "",
|
|
255
|
+
"kind": "ClusterTriggerAuthentication",
|
|
256
|
+
"secret_refs_count": len(secret_refs),
|
|
257
|
+
"env_refs_count": len(env_refs),
|
|
258
|
+
"has_pod_identity": "podIdentity" in spec,
|
|
259
|
+
"has_azure_identity": "azureKeyVault" in spec,
|
|
260
|
+
"has_hashicorp_vault": "hashiCorpVault" in spec,
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
"context": context or "current",
|
|
265
|
+
"total": len(auths),
|
|
266
|
+
"authentications": auths,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def keda_triggerauth_get(
|
|
271
|
+
name: str,
|
|
272
|
+
namespace: str = "",
|
|
273
|
+
kind: str = "TriggerAuthentication",
|
|
274
|
+
context: str = ""
|
|
275
|
+
) -> Dict[str, Any]:
|
|
276
|
+
"""Get detailed information about a TriggerAuthentication.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
name: Name of the TriggerAuthentication
|
|
280
|
+
namespace: Namespace (only for TriggerAuthentication, not ClusterTriggerAuthentication)
|
|
281
|
+
kind: TriggerAuthentication or ClusterTriggerAuthentication
|
|
282
|
+
context: Kubernetes context to use (optional)
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
Detailed TriggerAuthentication information
|
|
286
|
+
"""
|
|
287
|
+
if kind.lower() == "clustertriggerauthentication":
|
|
288
|
+
crd = "clustertriggerauthentications.keda.sh"
|
|
289
|
+
args = ["get", crd, name, "-o", "json"]
|
|
290
|
+
else:
|
|
291
|
+
crd = "triggerauthentications.keda.sh"
|
|
292
|
+
args = ["get", crd, name, "-n", namespace, "-o", "json"]
|
|
293
|
+
|
|
294
|
+
if not crd_exists(crd, context):
|
|
295
|
+
return {"success": False, "error": f"{crd} not found"}
|
|
296
|
+
|
|
297
|
+
result = _run_kubectl(args, context)
|
|
298
|
+
|
|
299
|
+
if result["success"]:
|
|
300
|
+
try:
|
|
301
|
+
data = json.loads(result["output"])
|
|
302
|
+
return {
|
|
303
|
+
"success": True,
|
|
304
|
+
"context": context or "current",
|
|
305
|
+
"authentication": data,
|
|
306
|
+
}
|
|
307
|
+
except json.JSONDecodeError:
|
|
308
|
+
return {"success": False, "error": "Failed to parse response"}
|
|
309
|
+
|
|
310
|
+
return {"success": False, "error": result.get("error", "Unknown error")}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def keda_hpa_list(
|
|
314
|
+
namespace: str = "",
|
|
315
|
+
context: str = "",
|
|
316
|
+
label_selector: str = ""
|
|
317
|
+
) -> Dict[str, Any]:
|
|
318
|
+
"""List HPAs managed by KEDA.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
namespace: Filter by namespace (empty for all namespaces)
|
|
322
|
+
context: Kubernetes context to use (optional)
|
|
323
|
+
label_selector: Label selector to filter resources
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
List of KEDA-managed HPAs
|
|
327
|
+
"""
|
|
328
|
+
# KEDA creates HPAs with specific labels
|
|
329
|
+
keda_label = "scaledobject.keda.sh/name"
|
|
330
|
+
selector = label_selector if label_selector else ""
|
|
331
|
+
|
|
332
|
+
args = ["get", "hpa", "-o", "json"]
|
|
333
|
+
if namespace:
|
|
334
|
+
args.extend(["-n", namespace])
|
|
335
|
+
else:
|
|
336
|
+
args.append("-A")
|
|
337
|
+
if selector:
|
|
338
|
+
args.extend(["-l", selector])
|
|
339
|
+
|
|
340
|
+
result = _run_kubectl(args, context)
|
|
341
|
+
if not result["success"]:
|
|
342
|
+
return {"success": False, "error": result.get("error", "Failed to list HPAs")}
|
|
343
|
+
|
|
344
|
+
try:
|
|
345
|
+
data = json.loads(result["output"])
|
|
346
|
+
items = data.get("items", [])
|
|
347
|
+
except json.JSONDecodeError:
|
|
348
|
+
return {"success": False, "error": "Failed to parse response"}
|
|
349
|
+
|
|
350
|
+
hpas = []
|
|
351
|
+
for item in items:
|
|
352
|
+
labels = item.get("metadata", {}).get("labels", {})
|
|
353
|
+
# Filter to KEDA-managed HPAs
|
|
354
|
+
if keda_label not in labels and "app.kubernetes.io/managed-by" not in labels:
|
|
355
|
+
continue
|
|
356
|
+
if labels.get("app.kubernetes.io/managed-by") != "keda-operator":
|
|
357
|
+
if keda_label not in labels:
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
spec = item.get("spec", {})
|
|
361
|
+
status = item.get("status", {})
|
|
362
|
+
|
|
363
|
+
hpas.append({
|
|
364
|
+
"name": item["metadata"]["name"],
|
|
365
|
+
"namespace": item["metadata"]["namespace"],
|
|
366
|
+
"scaledobject": labels.get(keda_label, ""),
|
|
367
|
+
"min_replicas": spec.get("minReplicas", 1),
|
|
368
|
+
"max_replicas": spec.get("maxReplicas", 10),
|
|
369
|
+
"current_replicas": status.get("currentReplicas", 0),
|
|
370
|
+
"desired_replicas": status.get("desiredReplicas", 0),
|
|
371
|
+
"current_metrics": status.get("currentMetrics", []),
|
|
372
|
+
"conditions": status.get("conditions", []),
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
"context": context or "current",
|
|
377
|
+
"total": len(hpas),
|
|
378
|
+
"hpas": hpas,
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def keda_detect(context: str = "") -> Dict[str, Any]:
|
|
383
|
+
"""Detect if KEDA is installed and its components.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
context: Kubernetes context to use (optional)
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
Detection results for KEDA
|
|
390
|
+
"""
|
|
391
|
+
return {
|
|
392
|
+
"context": context or "current",
|
|
393
|
+
"installed": crd_exists(SCALEDOBJECT_CRD, context),
|
|
394
|
+
"crds": {
|
|
395
|
+
"scaledobjects": crd_exists(SCALEDOBJECT_CRD, context),
|
|
396
|
+
"scaledjobs": crd_exists(SCALEDJOB_CRD, context),
|
|
397
|
+
"triggerauthentications": crd_exists(TRIGGERAUTH_CRD, context),
|
|
398
|
+
"clustertriggerauthentications": crd_exists(CLUSTERTRIGGERAUTH_CRD, context),
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def register_keda_tools(mcp: FastMCP, non_destructive: bool = False):
|
|
404
|
+
"""Register KEDA tools with the MCP server."""
|
|
405
|
+
|
|
406
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
407
|
+
def keda_scaledobjects_list_tool(
|
|
408
|
+
namespace: str = "",
|
|
409
|
+
context: str = "",
|
|
410
|
+
label_selector: str = ""
|
|
411
|
+
) -> str:
|
|
412
|
+
"""List KEDA ScaledObjects with their scaling status."""
|
|
413
|
+
return json.dumps(keda_scaledobjects_list(namespace, context, label_selector), indent=2)
|
|
414
|
+
|
|
415
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
416
|
+
def keda_scaledobject_get_tool(
|
|
417
|
+
name: str,
|
|
418
|
+
namespace: str,
|
|
419
|
+
context: str = ""
|
|
420
|
+
) -> str:
|
|
421
|
+
"""Get detailed information about a ScaledObject."""
|
|
422
|
+
return json.dumps(keda_scaledobject_get(name, namespace, context), indent=2)
|
|
423
|
+
|
|
424
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
425
|
+
def keda_scaledjobs_list_tool(
|
|
426
|
+
namespace: str = "",
|
|
427
|
+
context: str = "",
|
|
428
|
+
label_selector: str = ""
|
|
429
|
+
) -> str:
|
|
430
|
+
"""List KEDA ScaledJobs with their status."""
|
|
431
|
+
return json.dumps(keda_scaledjobs_list(namespace, context, label_selector), indent=2)
|
|
432
|
+
|
|
433
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
434
|
+
def keda_triggerauths_list_tool(
|
|
435
|
+
namespace: str = "",
|
|
436
|
+
context: str = "",
|
|
437
|
+
include_cluster: bool = True
|
|
438
|
+
) -> str:
|
|
439
|
+
"""List KEDA TriggerAuthentications and ClusterTriggerAuthentications."""
|
|
440
|
+
return json.dumps(keda_triggerauths_list(namespace, context, include_cluster), indent=2)
|
|
441
|
+
|
|
442
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
443
|
+
def keda_triggerauth_get_tool(
|
|
444
|
+
name: str,
|
|
445
|
+
namespace: str = "",
|
|
446
|
+
kind: str = "TriggerAuthentication",
|
|
447
|
+
context: str = ""
|
|
448
|
+
) -> str:
|
|
449
|
+
"""Get detailed information about a TriggerAuthentication."""
|
|
450
|
+
return json.dumps(keda_triggerauth_get(name, namespace, kind, context), indent=2)
|
|
451
|
+
|
|
452
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
453
|
+
def keda_hpa_list_tool(
|
|
454
|
+
namespace: str = "",
|
|
455
|
+
context: str = "",
|
|
456
|
+
label_selector: str = ""
|
|
457
|
+
) -> str:
|
|
458
|
+
"""List HPAs managed by KEDA."""
|
|
459
|
+
return json.dumps(keda_hpa_list(namespace, context, label_selector), indent=2)
|
|
460
|
+
|
|
461
|
+
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
|
|
462
|
+
def keda_detect_tool(context: str = "") -> str:
|
|
463
|
+
"""Detect if KEDA is installed and its components."""
|
|
464
|
+
return json.dumps(keda_detect(context), indent=2)
|