From 5074c99ac5426bc31f435158a22c4457739ea21a Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Fri, 21 Nov 2025 11:11:41 -0500 Subject: [PATCH] feat: add IsValid check for toolsets Signed-off-by: Calum Murray --- pkg/api/toolsets.go | 3 +++ pkg/mcp/mcp.go | 31 +++++++++++++++++++++++++------ pkg/toolsets/config/toolset.go | 4 ++++ pkg/toolsets/core/toolset.go | 4 ++++ pkg/toolsets/helm/toolset.go | 4 ++++ pkg/toolsets/kiali/toolset.go | 14 ++++++++++++++ pkg/toolsets/toolsets_test.go | 2 ++ 7 files changed, 56 insertions(+), 6 deletions(-) diff --git a/pkg/api/toolsets.go b/pkg/api/toolsets.go index c5960e3f..4ce8e321 100644 --- a/pkg/api/toolsets.go +++ b/pkg/api/toolsets.go @@ -44,6 +44,9 @@ type Toolset interface { // Will be used to generate documentation and help text. GetDescription() string GetTools(o internalk8s.Openshift) []ServerTool + // IsValid returns whether or not the toolset is valid on the current cluster + // Used to identify if toolsets should be disabled despite the config based on what is installed in the cluster + IsValid(k *internalk8s.Kubernetes) bool } type ToolCallRequest interface { diff --git a/pkg/mcp/mcp.go b/pkg/mcp/mcp.go index 6a4a6d2f..2a9e5970 100644 --- a/pkg/mcp/mcp.go +++ b/pkg/mcp/mcp.go @@ -120,12 +120,6 @@ func (s *Server) reloadKubernetesClusterProvider() error { ShouldIncludeTargetListTool(p.GetTargetParameterName(), targets), ) - mutator := WithTargetParameter( - p.GetDefaultTarget(), - p.GetTargetParameterName(), - targets, - ) - // TODO: No option to perform a full replacement of tools. // s.server.SetTools(m3labsServerTools...) @@ -136,6 +130,31 @@ func (s *Server) reloadKubernetesClusterProvider() error { applicableTools := make([]api.ServerTool, 0) s.enabledTools = make([]string, 0) for _, toolset := range s.configuration.Toolsets() { + // make sure that the toolset is valid for at least one target, otherwise don't add tools from it + toolTargets := []string{} + for _, target := range targets { + k, err := p.GetDerivedKubernetes(ctx, target) + if err != nil { + // don't error out - just continue, this is just to determine if a tool is valid or not + continue + } + + if toolset.IsValid(k) { + toolTargets = append(toolTargets, target) + } + } + + if len(toolTargets) == 0 { + // no targets for this toolset, don't add tools from it + continue + } + + mutator := WithTargetParameter( + p.GetDefaultTarget(), + p.GetTargetParameterName(), + targets, + ) + for _, tool := range toolset.GetTools(p) { tool := mutator(tool) if !filter(tool) { diff --git a/pkg/toolsets/config/toolset.go b/pkg/toolsets/config/toolset.go index 5d641fe5..0a11fd77 100644 --- a/pkg/toolsets/config/toolset.go +++ b/pkg/toolsets/config/toolset.go @@ -26,6 +26,10 @@ func (t *Toolset) GetTools(_ internalk8s.Openshift) []api.ServerTool { ) } +func (t *Toolset) IsValid(_ *internalk8s.Kubernetes) bool { + return true +} + func init() { toolsets.Register(&Toolset{}) } diff --git a/pkg/toolsets/core/toolset.go b/pkg/toolsets/core/toolset.go index dfd61f42..fde47381 100644 --- a/pkg/toolsets/core/toolset.go +++ b/pkg/toolsets/core/toolset.go @@ -30,6 +30,10 @@ func (t *Toolset) GetTools(o internalk8s.Openshift) []api.ServerTool { ) } +func (t *Toolset) IsValid(_ *internalk8s.Kubernetes) bool { + return true // core is always valid +} + func init() { toolsets.Register(&Toolset{}) } diff --git a/pkg/toolsets/helm/toolset.go b/pkg/toolsets/helm/toolset.go index dbe75c1e..75652ecc 100644 --- a/pkg/toolsets/helm/toolset.go +++ b/pkg/toolsets/helm/toolset.go @@ -26,6 +26,10 @@ func (t *Toolset) GetTools(_ internalk8s.Openshift) []api.ServerTool { ) } +func (t *Toolset) IsValid(_ *internalk8s.Kubernetes) bool { + return true +} + func init() { toolsets.Register(&Toolset{}) } diff --git a/pkg/toolsets/kiali/toolset.go b/pkg/toolsets/kiali/toolset.go index c89afcd4..58e6e609 100644 --- a/pkg/toolsets/kiali/toolset.go +++ b/pkg/toolsets/kiali/toolset.go @@ -1,6 +1,7 @@ package kiali import ( + "context" "slices" "github.com/containers/kubernetes-mcp-server/pkg/api" @@ -39,6 +40,19 @@ func (t *Toolset) GetTools(_ internalk8s.Openshift) []api.ServerTool { ) } +func (t *Toolset) IsValid(k *internalk8s.Kubernetes) bool { + // Create a Kiali client + kialiClient := k.NewKiali() + + // Check if Kiali is actually accessible by making a lightweight API call + // We'll try to get the mesh status as it's a simple endpoint that doesn't require parameters + ctx := context.Background() + _, err := kialiClient.MeshStatus(ctx) + + // If we can successfully call Kiali, it's valid + return err == nil +} + func init() { toolsets.Register(&Toolset{}) } diff --git a/pkg/toolsets/toolsets_test.go b/pkg/toolsets/toolsets_test.go index 05af11a8..a01e105b 100644 --- a/pkg/toolsets/toolsets_test.go +++ b/pkg/toolsets/toolsets_test.go @@ -35,6 +35,8 @@ func (t *TestToolset) GetDescription() string { return t.description } func (t *TestToolset) GetTools(_ kubernetes.Openshift) []api.ServerTool { return nil } +func (t *TestToolset) IsValid(_ *kubernetes.Kubernetes) bool { return true } + var _ api.Toolset = (*TestToolset)(nil) func (s *ToolsetsSuite) TestToolsetNames() {