From b68ae65d7da4a042fab7f2b7f2db6ae9d462fff7 Mon Sep 17 00:00:00 2001 From: basebandit Date: Thu, 7 May 2026 14:03:34 +0300 Subject: [PATCH] feat(tools): add MCP tool annotations to all 66 tools --- tools/annotations.go | 55 ++++++++++++++++++++++++++++++++++++++++++++ tools/configmap.go | 5 ++++ tools/context.go | 7 ++++++ tools/cronjob.go | 7 ++++++ tools/deployment.go | 13 +++++++++++ tools/ingress.go | 5 ++++ tools/job.go | 5 ++++ tools/namespace.go | 5 ++++ tools/operations.go | 3 +++ tools/pod.go | 5 ++++ tools/secret.go | 5 ++++ tools/service.go | 6 +++++ 12 files changed, 121 insertions(+) create mode 100644 tools/annotations.go diff --git a/tools/annotations.go b/tools/annotations.go new file mode 100644 index 0000000..2e203c1 --- /dev/null +++ b/tools/annotations.go @@ -0,0 +1,55 @@ +package tools + +import "github.com/mark3labs/mcp-go/mcp" + +// readOnlyAnnotation is for tools that don't change cluster state. +// Repeated calls have no additional effect (idempotent). The cluster is an +// external system, so openWorld is true. +func readOnlyAnnotation(title string) mcp.ToolOption { + return mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: title, + ReadOnlyHint: mcp.ToBoolPtr(true), + DestructiveHint: mcp.ToBoolPtr(false), + IdempotentHint: mcp.ToBoolPtr(true), + OpenWorldHint: mcp.ToBoolPtr(true), + }) +} + +// destructiveAnnotation is for tools that delete or otherwise destroy +// cluster state. Not idempotent — a second delete typically returns +// "not found". +func destructiveAnnotation(title string) mcp.ToolOption { + return mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: title, + ReadOnlyHint: mcp.ToBoolPtr(false), + DestructiveHint: mcp.ToBoolPtr(true), + IdempotentHint: mcp.ToBoolPtr(false), + OpenWorldHint: mcp.ToBoolPtr(true), + }) +} + +// creationAnnotation is for tools that create a new resource. Not +// destructive in the data-loss sense, but not idempotent — recreating a +// resource that already exists errors with "already exists". +func creationAnnotation(title string) mcp.ToolOption { + return mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: title, + ReadOnlyHint: mcp.ToBoolPtr(false), + DestructiveHint: mcp.ToBoolPtr(false), + IdempotentHint: mcp.ToBoolPtr(false), + OpenWorldHint: mcp.ToBoolPtr(true), + }) +} + +// idempotentMutationAnnotation is for update / scale / suspend / resume +// tools that drive a resource toward a desired final state. Repeating +// with the same arguments produces no further change. +func idempotentMutationAnnotation(title string) mcp.ToolOption { + return mcp.WithToolAnnotation(mcp.ToolAnnotation{ + Title: title, + ReadOnlyHint: mcp.ToBoolPtr(false), + DestructiveHint: mcp.ToBoolPtr(false), + IdempotentHint: mcp.ToBoolPtr(true), + OpenWorldHint: mcp.ToBoolPtr(true), + }) +} diff --git a/tools/configmap.go b/tools/configmap.go index c325301..46721f8 100644 --- a/tools/configmap.go +++ b/tools/configmap.go @@ -45,6 +45,7 @@ func RegisterConfigMapTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterConfigMapToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory ConfigMapFactory) { createConfigMapTool := mcp.NewTool("create_configmap", mcp.WithDescription("Create a new ConfigMap in the specified namespace"), + creationAnnotation("Create configmap"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the ConfigMap"), @@ -69,6 +70,7 @@ func RegisterConfigMapToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMana getConfigMapTool := mcp.NewTool("get_configmap", mcp.WithDescription("Get detailed information about a specific ConfigMap"), + readOnlyAnnotation("Get configmap"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the ConfigMap"), @@ -81,6 +83,7 @@ func RegisterConfigMapToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMana listConfigMapsTool := mcp.NewTool("list_configmaps", mcp.WithDescription("List ConfigMaps in the current namespace or across all namespaces"), + readOnlyAnnotation("List configmaps"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list ConfigMaps across all namespaces"), ), @@ -95,6 +98,7 @@ func RegisterConfigMapToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMana deleteConfigMapTool := mcp.NewTool("delete_configmap", mcp.WithDescription("Delete a ConfigMap from the specified namespace"), + destructiveAnnotation("Delete configmap"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the ConfigMap to delete"), @@ -107,6 +111,7 @@ func RegisterConfigMapToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMana updateConfigMapTool := mcp.NewTool("update_configmap", mcp.WithDescription("Update an existing ConfigMap"), + idempotentMutationAnnotation("Update configmap"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the ConfigMap to update"), diff --git a/tools/context.go b/tools/context.go index bf45612..1b42b4b 100644 --- a/tools/context.go +++ b/tools/context.go @@ -14,16 +14,19 @@ import ( func RegisterContextTools(s kai.ServerInterface, cm kai.ClusterManager) { listContextsTool := mcp.NewTool("list_contexts", mcp.WithDescription("List all available Kubernetes contexts"), + readOnlyAnnotation("List contexts"), ) s.AddTool(listContextsTool, listContextsHandler(cm)) getCurrentContextTool := mcp.NewTool("get_current_context", mcp.WithDescription("Get the currently active Kubernetes context"), + readOnlyAnnotation("Get current context"), ) s.AddTool(getCurrentContextTool, getCurrentContextHandler(cm)) switchContextTool := mcp.NewTool("switch_context", mcp.WithDescription("Switch to a different Kubernetes context"), + idempotentMutationAnnotation("Switch context"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the context to switch to"), @@ -33,6 +36,7 @@ func RegisterContextTools(s kai.ServerInterface, cm kai.ClusterManager) { loadKubeconfigTool := mcp.NewTool("load_kubeconfig", mcp.WithDescription("Load a kubeconfig file and register it as a new context"), + creationAnnotation("Load kubeconfig"), mcp.WithString("name", mcp.Required(), mcp.Description("Name to assign to this context"), @@ -45,6 +49,7 @@ func RegisterContextTools(s kai.ServerInterface, cm kai.ClusterManager) { deleteContextTool := mcp.NewTool("delete_context", mcp.WithDescription("Remove a context from the manager"), + destructiveAnnotation("Delete context"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the context to delete"), @@ -54,6 +59,7 @@ func RegisterContextTools(s kai.ServerInterface, cm kai.ClusterManager) { renameContextTool := mcp.NewTool("rename_context", mcp.WithDescription("Rename an existing context"), + creationAnnotation("Rename context"), mcp.WithString("old_name", mcp.Required(), mcp.Description("Current name of the context"), @@ -67,6 +73,7 @@ func RegisterContextTools(s kai.ServerInterface, cm kai.ClusterManager) { describeContextTool := mcp.NewTool("describe_context", mcp.WithDescription("Get detailed information about a specific context"), + readOnlyAnnotation("Describe context"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the context to describe"), diff --git a/tools/cronjob.go b/tools/cronjob.go index 5049eb2..ef89827 100644 --- a/tools/cronjob.go +++ b/tools/cronjob.go @@ -56,6 +56,7 @@ func RegisterCronJobTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory CronJobFactory) { createCronJobTool := mcp.NewTool("create_cronjob", mcp.WithDescription("Create a new CronJob in the specified namespace"), + creationAnnotation("Create cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob"), @@ -115,6 +116,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage getCronJobTool := mcp.NewTool("get_cronjob", mcp.WithDescription("Get information about a specific CronJob"), + readOnlyAnnotation("Get cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob"), @@ -127,6 +129,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage listCronJobsTool := mcp.NewTool("list_cronjobs", mcp.WithDescription("List CronJobs in the current namespace or across all namespaces"), + readOnlyAnnotation("List cronjobs"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list CronJobs across all namespaces"), ), @@ -141,6 +144,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage deleteCronJobTool := mcp.NewTool("delete_cronjob", mcp.WithDescription("Delete a CronJob from the specified namespace"), + destructiveAnnotation("Delete cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob to delete"), @@ -153,6 +157,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage updateCronJobTool := mcp.NewTool("update_cronjob", mcp.WithDescription("Update an existing CronJob"), + idempotentMutationAnnotation("Update cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob to update"), @@ -180,6 +185,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage suspendCronJobTool := mcp.NewTool("suspend_cronjob", mcp.WithDescription("Suspend a CronJob to prevent it from creating new jobs"), + idempotentMutationAnnotation("Suspend cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob to suspend"), @@ -192,6 +198,7 @@ func RegisterCronJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage resumeCronJobTool := mcp.NewTool("resume_cronjob", mcp.WithDescription("Resume a suspended CronJob"), + idempotentMutationAnnotation("Resume cronjob"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the CronJob to resume"), diff --git a/tools/deployment.go b/tools/deployment.go index d823fc3..ff73fbf 100644 --- a/tools/deployment.go +++ b/tools/deployment.go @@ -47,6 +47,7 @@ func RegisterDeploymentTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory DeploymentFactory) { listDeploymentTool := mcp.NewTool("list_deployments", mcp.WithDescription("List deployments in the current namespace or across all namespaces"), + readOnlyAnnotation("List deployments"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list deployments across all namespaces"), ), @@ -62,6 +63,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan describeDeploymentTool := mcp.NewTool("describe_deployment", mcp.WithDescription("Get detailed information about a specific deployment"), + readOnlyAnnotation("Describe deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -75,6 +77,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan createDeploymentTool := mcp.NewTool("create_deployment", mcp.WithDescription("Create a new deployment in the current namespace"), + creationAnnotation("Create deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -110,6 +113,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan getDeploymentTool := mcp.NewTool("get_deployment", mcp.WithDescription("Get basic information about a specific deployment"), + readOnlyAnnotation("Get deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -123,6 +127,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan updateDeploymentTool := mcp.NewTool("update_deployment", mcp.WithDescription("Update an existing deployment"), + idempotentMutationAnnotation("Update deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment to update"), @@ -157,6 +162,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan deleteDeploymentTool := mcp.NewTool("delete_deployment", mcp.WithDescription("Delete a deployment from the cluster"), + destructiveAnnotation("Delete deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment to delete"), @@ -170,6 +176,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan scaleDeploymentTool := mcp.NewTool("scale_deployment", mcp.WithDescription("Scale a deployment to a specified number of replicas"), + idempotentMutationAnnotation("Scale deployment"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment to scale"), @@ -187,6 +194,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutStatusTool := mcp.NewTool("rollout_status_deployment", mcp.WithDescription("Check the rollout status of a deployment"), + readOnlyAnnotation("Get rollout status"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -200,6 +208,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutHistoryTool := mcp.NewTool("rollout_history_deployment", mcp.WithDescription("View the rollout history of a deployment"), + readOnlyAnnotation("Get rollout history"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -213,6 +222,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutUndoTool := mcp.NewTool("rollout_undo_deployment", mcp.WithDescription("Roll back a deployment to a previous revision"), + destructiveAnnotation("Undo rollout"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -229,6 +239,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutRestartTool := mcp.NewTool("rollout_restart_deployment", mcp.WithDescription("Restart a deployment by recreating its pods"), + creationAnnotation("Restart rollout"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -242,6 +253,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutPauseTool := mcp.NewTool("rollout_pause_deployment", mcp.WithDescription("Pause a deployment rollout"), + idempotentMutationAnnotation("Pause rollout"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), @@ -255,6 +267,7 @@ func RegisterDeploymentToolsWithFactory(s kai.ServerInterface, cm kai.ClusterMan rolloutResumeTool := mcp.NewTool("rollout_resume_deployment", mcp.WithDescription("Resume a paused deployment rollout"), + idempotentMutationAnnotation("Resume rollout"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the deployment"), diff --git a/tools/ingress.go b/tools/ingress.go index 75ca001..0148168 100644 --- a/tools/ingress.go +++ b/tools/ingress.go @@ -47,6 +47,7 @@ func RegisterIngressTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterIngressToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory IngressFactory) { createIngressTool := mcp.NewTool("create_ingress", mcp.WithDescription("Create a new Ingress in the specified namespace for HTTP/HTTPS routing"), + creationAnnotation("Create ingress"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Ingress"), @@ -77,6 +78,7 @@ func RegisterIngressToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage getIngressTool := mcp.NewTool("get_ingress", mcp.WithDescription("Get information about a specific Ingress"), + readOnlyAnnotation("Get ingress"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Ingress"), @@ -89,6 +91,7 @@ func RegisterIngressToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage listIngressesTool := mcp.NewTool("list_ingresses", mcp.WithDescription("List Ingresses in the current namespace or across all namespaces"), + readOnlyAnnotation("List ingresses"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list Ingresses across all namespaces"), ), @@ -103,6 +106,7 @@ func RegisterIngressToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage updateIngressTool := mcp.NewTool("update_ingress", mcp.WithDescription("Update an existing Ingress"), + idempotentMutationAnnotation("Update ingress"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Ingress to update"), @@ -133,6 +137,7 @@ func RegisterIngressToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage deleteIngressTool := mcp.NewTool("delete_ingress", mcp.WithDescription("Delete an Ingress from the specified namespace"), + destructiveAnnotation("Delete ingress"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Ingress to delete"), diff --git a/tools/job.go b/tools/job.go index 8b2f7c8..f541910 100644 --- a/tools/job.go +++ b/tools/job.go @@ -52,6 +52,7 @@ func RegisterJobTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory JobFactory) { createJobTool := mcp.NewTool("create_job", mcp.WithDescription("Create a new Job in the specified namespace"), + creationAnnotation("Create job"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Job"), @@ -98,6 +99,7 @@ func RegisterJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f getJobTool := mcp.NewTool("get_job", mcp.WithDescription("Get information about a specific Job"), + readOnlyAnnotation("Get job"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Job"), @@ -110,6 +112,7 @@ func RegisterJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f listJobsTool := mcp.NewTool("list_jobs", mcp.WithDescription("List Jobs in the current namespace or across all namespaces"), + readOnlyAnnotation("List jobs"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list Jobs across all namespaces"), ), @@ -124,6 +127,7 @@ func RegisterJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f deleteJobTool := mcp.NewTool("delete_job", mcp.WithDescription("Delete a Job from the specified namespace"), + destructiveAnnotation("Delete job"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Job to delete"), @@ -136,6 +140,7 @@ func RegisterJobToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f updateJobTool := mcp.NewTool("update_job", mcp.WithDescription("Update an existing Job (limited to mutable fields like labels and parallelism)"), + idempotentMutationAnnotation("Update job"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Job to update"), diff --git a/tools/namespace.go b/tools/namespace.go index b0ea604..4e1e210 100644 --- a/tools/namespace.go +++ b/tools/namespace.go @@ -13,6 +13,7 @@ import ( func RegisterNamespaceTools(s kai.ServerInterface, cm kai.ClusterManager) { createNamespaceTool := mcp.NewTool("create_namespace", mcp.WithDescription("Create a new Kubernetes namespace"), + creationAnnotation("Create namespace"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the namespace to create"), @@ -28,6 +29,7 @@ func RegisterNamespaceTools(s kai.ServerInterface, cm kai.ClusterManager) { getNamespaceTool := mcp.NewTool("get_namespace", mcp.WithDescription("Get detailed information about a specific namespace"), + readOnlyAnnotation("Get namespace"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the namespace to get"), @@ -37,6 +39,7 @@ func RegisterNamespaceTools(s kai.ServerInterface, cm kai.ClusterManager) { listNamespacesTool := mcp.NewTool("list_namespaces", mcp.WithDescription("List all namespaces in the cluster"), + readOnlyAnnotation("List namespaces"), mcp.WithString("label_selector", mcp.Description("Label selector to filter namespaces (e.g., 'env=prod,tier=backend')"), ), @@ -45,6 +48,7 @@ func RegisterNamespaceTools(s kai.ServerInterface, cm kai.ClusterManager) { deleteNamespaceTool := mcp.NewTool("delete_namespace", mcp.WithDescription("Delete a namespace or namespaces matching label selector"), + destructiveAnnotation("Delete namespace"), mcp.WithString("name", mcp.Description("Name of the namespace to delete"), ), @@ -56,6 +60,7 @@ func RegisterNamespaceTools(s kai.ServerInterface, cm kai.ClusterManager) { updateNamespaceTool := mcp.NewTool("update_namespace", mcp.WithDescription("Update an existing namespace"), + idempotentMutationAnnotation("Update namespace"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the namespace to update"), diff --git a/tools/operations.go b/tools/operations.go index 9712ffc..2b9971e 100644 --- a/tools/operations.go +++ b/tools/operations.go @@ -26,6 +26,7 @@ func RegisterOperationsTools(s kai.ServerInterface, cm kai.ClusterManager) { func registerPortForwardTools(s kai.ServerInterface, manager *cluster.Manager) { startPortForwardTool := mcp.NewTool("start_port_forward", mcp.WithDescription("Start port forwarding to a pod or service. Similar to 'kubectl port-forward'"), + creationAnnotation("Start port forward"), mcp.WithString("target", mcp.Required(), mcp.Description("Target to forward to. Use 'pod/name' or 'service/name' or 'svc/name' format"), @@ -43,6 +44,7 @@ func registerPortForwardTools(s kai.ServerInterface, manager *cluster.Manager) { stopPortForwardTool := mcp.NewTool("stop_port_forward", mcp.WithDescription("Stop an active port forwarding session"), + idempotentMutationAnnotation("Stop port forward"), mcp.WithString("session_id", mcp.Required(), mcp.Description("ID of the port forward session to stop (e.g., 'pf-1')"), @@ -53,6 +55,7 @@ func registerPortForwardTools(s kai.ServerInterface, manager *cluster.Manager) { listPortForwardsTool := mcp.NewTool("list_port_forwards", mcp.WithDescription("List all active port forwarding sessions"), + readOnlyAnnotation("List port forwards"), ) s.AddTool(listPortForwardsTool, listPortForwardsHandler(manager)) diff --git a/tools/pod.go b/tools/pod.go index 8075f23..f1e8ce0 100644 --- a/tools/pod.go +++ b/tools/pod.go @@ -44,6 +44,7 @@ func RegisterPodTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterPodToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory PodFactory) { createPodTool := mcp.NewTool("create_pod", mcp.WithDescription("Create a new pod in the current namespace"), + creationAnnotation("Create pod"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the pod"), @@ -94,6 +95,7 @@ func RegisterPodToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f listPodTools := mcp.NewTool("list_pods", mcp.WithDescription("List pods in the current namespace or across all namespaces"), + readOnlyAnnotation("List pods"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list pods across all namespaces"), ), @@ -115,6 +117,7 @@ func RegisterPodToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f getPodTool := mcp.NewTool("get_pod", mcp.WithDescription("Get detailed information about a specific pod"), + readOnlyAnnotation("Get pod"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the pod"), @@ -128,6 +131,7 @@ func RegisterPodToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f deletePodTool := mcp.NewTool("delete_pod", mcp.WithDescription("Delete a pod by name"), + destructiveAnnotation("Delete pod"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the pod to delete"), @@ -142,6 +146,7 @@ func RegisterPodToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, f streamLogsTool := mcp.NewTool("stream_logs", mcp.WithDescription("Stream logs from a container in a pod"), + readOnlyAnnotation("Stream pod logs"), mcp.WithString("pod", mcp.Required(), mcp.Description("Name of the pod"), diff --git a/tools/secret.go b/tools/secret.go index 5a0e0c8..0c238d2 100644 --- a/tools/secret.go +++ b/tools/secret.go @@ -46,6 +46,7 @@ func RegisterSecretTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterSecretToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory SecretFactory) { createSecretTool := mcp.NewTool("create_secret", mcp.WithDescription("Create a new Secret in the specified namespace"), + creationAnnotation("Create secret"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Secret"), @@ -73,6 +74,7 @@ func RegisterSecretToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager getSecretTool := mcp.NewTool("get_secret", mcp.WithDescription("Get information about a specific Secret (values are masked for security)"), + readOnlyAnnotation("Get secret"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Secret"), @@ -85,6 +87,7 @@ func RegisterSecretToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager listSecretsTool := mcp.NewTool("list_secrets", mcp.WithDescription("List Secrets in the current namespace or across all namespaces"), + readOnlyAnnotation("List secrets"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list Secrets across all namespaces"), ), @@ -99,6 +102,7 @@ func RegisterSecretToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager deleteSecretTool := mcp.NewTool("delete_secret", mcp.WithDescription("Delete a Secret from the specified namespace"), + destructiveAnnotation("Delete secret"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Secret to delete"), @@ -111,6 +115,7 @@ func RegisterSecretToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager updateSecretTool := mcp.NewTool("update_secret", mcp.WithDescription("Update an existing Secret"), + idempotentMutationAnnotation("Update secret"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the Secret to update"), diff --git a/tools/service.go b/tools/service.go index 2599397..1d705dc 100644 --- a/tools/service.go +++ b/tools/service.go @@ -61,6 +61,7 @@ func RegisterServiceTools(s kai.ServerInterface, cm kai.ClusterManager) { func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManager, factory ServiceFactory) { listServiceTool := mcp.NewTool("list_services", mcp.WithDescription("List services in the current namespace or across all namespaces"), + readOnlyAnnotation("List services"), mcp.WithBoolean("all_namespaces", mcp.Description("Whether to list services across all namespaces"), ), @@ -76,6 +77,7 @@ func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage getServiceTool := mcp.NewTool("get_service", mcp.WithDescription("Get detailed information about a specific service"), + readOnlyAnnotation("Get service"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the service"), @@ -89,6 +91,7 @@ func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage createServiceTool := mcp.NewTool("create_service", mcp.WithDescription("Create a new service in the current namespace"), + creationAnnotation("Create service"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the service"), @@ -127,6 +130,7 @@ func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage deleteServiceTool := mcp.NewTool("delete_service", mcp.WithDescription("Delete a service or multiple services matching criteria from the current namespace"), + destructiveAnnotation("Delete service"), mcp.WithString("name", mcp.Description("Name of the specific service to delete (either name or labels must be provided)"), ), @@ -142,6 +146,7 @@ func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage updateServiceTool := mcp.NewTool("update_service", mcp.WithDescription("Update an existing service"), + idempotentMutationAnnotation("Update service"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the service to update"), @@ -179,6 +184,7 @@ func RegisterServiceToolsWithFactory(s kai.ServerInterface, cm kai.ClusterManage patchServiceTool := mcp.NewTool("patch_service", mcp.WithDescription("Apply a partial update to an existing service"), + idempotentMutationAnnotation("Patch service"), mcp.WithString("name", mcp.Required(), mcp.Description("Name of the service to patch"),