Repository: containers/kubernetes-mcp-server

Issue:
Operations like `pods_list` are too verbose and blow the model context window
My clusters have a few hundred microservices and `pods_list` on such a cluster quickly blows the entire context window. For instance, listing one of my namespaces I end up with 700,000 tokens because this operation seems to be describing every single pod. This much detail is bad for scaling.

`pods_list` should literally just list the pods, or provide a way to just list the pods, with filters available for extra granularity.

Hints from issue comments:
@manusa: I'm currently working on adding a few options that go in this line.

To summarize:
- `--profile` flag:
  Adds the option to limit the number of tools depending on the selected profile
  - `full`: all of the tools are enabled
  - `slm`: (Small Language Model), only essential tools are enabled (e.g. no Helm)
- Provide a way to configure the output.
  I guess something like what `kubectl -o --output` does.
  `yaml`, `name`, ...
  Exactly what you are requesting.

Please, let me know your thoughts about this.
Will probably have something ready by the end of today ;)@dbsanfte: Yes a way to filter the output seems to be exactly what we're missing. I can add filter instructions to my model's instruction prompt to make sure it always uses the filters to avoid a big dump of spam :)@eranco74: +1 for this issue.
I belive https://github.com/manusa/kubernetes-mcp-server/pull/87 should help filter the  pods.
Regarding the output formatting the standard way of doing it in kubectl is:  `-o custom-columns` or ` -o jsonpath` 
Although this server doesn't use kubectl it shouldn't be to complicated to filter the results with a provided  jsonpath  @manusa: The behavior has changed to list resources as a plain-text, human-readable table by default.
The previous behavior can be restored by passing the appropriate configuration (`--list-output yaml`)

This change is effective starting on [v0.0.40](https://github.com/manusa/kubernetes-mcp-server/releases/tag/v0.0.40)

Please, share any feedback you may have, it is much appreciated 🙏

Solution patch:
diff --git a/pkg/kubernetes-mcp-server/cmd/root.go b/pkg/kubernetes-mcp-server/cmd/root.go
index 8d1d2c2..53d8598 100644
--- a/pkg/kubernetes-mcp-server/cmd/root.go
+++ b/pkg/kubernetes-mcp-server/cmd/root.go
@@ -5,6 +5,7 @@ import (
 	"flag"
 	"fmt"
 	"github.com/manusa/kubernetes-mcp-server/pkg/mcp"
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	"github.com/manusa/kubernetes-mcp-server/pkg/version"
 	"github.com/mark3labs/mcp-go/server"
 	"github.com/spf13/cobra"
@@ -46,8 +47,14 @@ Kubernetes Model Context Protocol (MCP) server
 			fmt.Printf("Invalid profile name: %s, valid names are: %s\n", viper.GetString("profile"), strings.Join(mcp.ProfileNames, ", "))
 			os.Exit(1)
 		}
+		o := output.FromString(viper.GetString("output"))
+		if o == nil {
+			fmt.Printf("Invalid output name: %s, valid names are: %s\n", viper.GetString("output"), strings.Join(output.Names, ", "))
+			os.Exit(1)
+		}
 		klog.V(1).Info("Starting kubernetes-mcp-server")
 		klog.V(1).Infof(" - Profile: %s", profile.GetName())
+		klog.V(1).Infof(" - Output: %s", o.GetName())
 		klog.V(1).Infof(" - Read-only mode: %t", viper.GetBool("read-only"))
 		klog.V(1).Infof(" - Disable destructive tools: %t", viper.GetBool("disable-destructive"))
 		if viper.GetBool("version") {
@@ -56,6 +63,7 @@ Kubernetes Model Context Protocol (MCP) server
 		}
 		mcpServer, err := mcp.NewSever(mcp.Configuration{
 			Profile:            profile,
+			Output:             o,
 			ReadOnly:           viper.GetBool("read-only"),
 			DisableDestructive: viper.GetBool("disable-destructive"),
 			Kubeconfig:         viper.GetString("kubeconfig"),
@@ -121,14 +129,21 @@ func (p *profileFlag) Type() string {
 	return "profile"
 }
 
-func init() {
+// flagInit initializes the flags for the root command.
+// Exposed for testing purposes.
+func flagInit() {
 	rootCmd.Flags().BoolP("version", "v", false, "Print version information and quit")
 	rootCmd.Flags().IntP("log-level", "", 0, "Set the log level (from 0 to 9)")
 	rootCmd.Flags().IntP("sse-port", "", 0, "Start a SSE server on the specified port")
 	rootCmd.Flags().StringP("sse-base-url", "", "", "SSE public base URL to use when sending the endpoint message (e.g. https://example.com)")
 	rootCmd.Flags().StringP("kubeconfig", "", "", "Path to the kubeconfig file to use for authentication")
-	rootCmd.Flags().String("profile", "full", "MCP profile to use (one of: "+strings.Join(mcp.ProfileNames, ", ")+")")
+	rootCmd.Flags().String("profile", "full", "MCP profile to use (one of: "+strings.Join(mcp.ProfileNames, ", ")+") default is full")
+	rootCmd.Flags().String("output", "yaml", "Output format for resources (one of: "+strings.Join(output.Names, ", ")+") default is yaml")
 	rootCmd.Flags().Bool("read-only", false, "If true, only tools annotated with readOnlyHint=true are exposed")
 	rootCmd.Flags().Bool("disable-destructive", false, "If true, tools annotated with destructiveHint=true are disabled")
 	_ = viper.BindPFlags(rootCmd.Flags())
 }
+
+func init() {
+	flagInit()
+}
diff --git a/pkg/kubernetes/configuration.go b/pkg/kubernetes/configuration.go
index 97ccf22..4b7f884 100644
--- a/pkg/kubernetes/configuration.go
+++ b/pkg/kubernetes/configuration.go
@@ -1,6 +1,7 @@
 package kubernetes
 
 import (
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@@ -109,5 +110,5 @@ func (k *Kubernetes) ConfigurationView(minify bool) (string, error) {
 	if err != nil {
 		return "", err
 	}
-	return marshal(convertedObj)
+	return output.MarshalYaml(convertedObj)
 }
diff --git a/pkg/kubernetes/events.go b/pkg/kubernetes/events.go
index a8db246..cbe0eb2 100644
--- a/pkg/kubernetes/events.go
+++ b/pkg/kubernetes/events.go
@@ -3,6 +3,7 @@ package kubernetes
 import (
 	"context"
 	"fmt"
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
@@ -46,7 +47,7 @@ func (k *Kubernetes) EventsList(ctx context.Context, namespace string) (string,
 			"Message": strings.TrimSpace(event.Message),
 		})
 	}
-	yamlEvents, err := marshal(eventMap)
+	yamlEvents, err := output.MarshalYaml(eventMap)
 	if err != nil {
 		return "", err
 	}
diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go
index a473570..70d9b32 100644
--- a/pkg/kubernetes/kubernetes.go
+++ b/pkg/kubernetes/kubernetes.go
@@ -6,7 +6,6 @@ import (
 	"github.com/manusa/kubernetes-mcp-server/pkg/helm"
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/discovery"
 	"k8s.io/client-go/discovery/cached/memory"
@@ -18,7 +17,6 @@ import (
 	"k8s.io/client-go/tools/clientcmd"
 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 	"k8s.io/klog/v2"
-	"sigs.k8s.io/yaml"
 	"strings"
 )
 
@@ -164,25 +162,3 @@ func (k *Kubernetes) Derived(ctx context.Context) *Kubernetes {
 	derived.Helm = helm.NewHelm(derived)
 	return derived
 }
-
-func marshal(v any) (string, error) {
-	switch t := v.(type) {
-	case []unstructured.Unstructured:
-		for i := range t {
-			t[i].SetManagedFields(nil)
-		}
-	case []*unstructured.Unstructured:
-		for i := range t {
-			t[i].SetManagedFields(nil)
-		}
-	case unstructured.Unstructured:
-		t.SetManagedFields(nil)
-	case *unstructured.Unstructured:
-		t.SetManagedFields(nil)
-	}
-	ret, err := yaml.Marshal(v)
-	if err != nil {
-		return "", err
-	}
-	return string(ret), nil
-}
diff --git a/pkg/kubernetes/namespaces.go b/pkg/kubernetes/namespaces.go
index c817bcb..931de8e 100644
--- a/pkg/kubernetes/namespaces.go
+++ b/pkg/kubernetes/namespaces.go
@@ -2,16 +2,17 @@ package kubernetes
 
 import (
 	"context"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 )
 
-func (k *Kubernetes) NamespacesList(ctx context.Context) (string, error) {
+func (k *Kubernetes) NamespacesList(ctx context.Context) ([]unstructured.Unstructured, error) {
 	return k.ResourcesList(ctx, &schema.GroupVersionKind{
 		Group: "", Version: "v1", Kind: "Namespace",
 	}, "")
 }
 
-func (k *Kubernetes) ProjectsList(ctx context.Context) (string, error) {
+func (k *Kubernetes) ProjectsList(ctx context.Context) ([]unstructured.Unstructured, error) {
 	return k.ResourcesList(ctx, &schema.GroupVersionKind{
 		Group: "project.openshift.io", Version: "v1", Kind: "Project",
 	}, "")
diff --git a/pkg/kubernetes/pods.go b/pkg/kubernetes/pods.go
index 0e48507..791641e 100644
--- a/pkg/kubernetes/pods.go
+++ b/pkg/kubernetes/pods.go
@@ -18,19 +18,19 @@ import (
 	"k8s.io/client-go/tools/remotecommand"
 )
 
-func (k *Kubernetes) PodsListInAllNamespaces(ctx context.Context, labelSelector string) (string, error) {
+func (k *Kubernetes) PodsListInAllNamespaces(ctx context.Context, labelSelector string) ([]unstructured.Unstructured, error) {
 	return k.ResourcesList(ctx, &schema.GroupVersionKind{
 		Group: "", Version: "v1", Kind: "Pod",
 	}, "", labelSelector)
 }
 
-func (k *Kubernetes) PodsListInNamespace(ctx context.Context, namespace string, labelSelector string) (string, error) {
+func (k *Kubernetes) PodsListInNamespace(ctx context.Context, namespace string, labelSelector string) ([]unstructured.Unstructured, error) {
 	return k.ResourcesList(ctx, &schema.GroupVersionKind{
 		Group: "", Version: "v1", Kind: "Pod",
 	}, namespace, labelSelector)
 }
 
-func (k *Kubernetes) PodsGet(ctx context.Context, namespace, name string) (string, error) {
+func (k *Kubernetes) PodsGet(ctx context.Context, namespace, name string) (*unstructured.Unstructured, error) {
 	return k.ResourcesGet(ctx, &schema.GroupVersionKind{
 		Group: "", Version: "v1", Kind: "Pod",
 	}, k.NamespaceOrDefault(namespace), name)
diff --git a/pkg/kubernetes/resources.go b/pkg/kubernetes/resources.go
index 603c57a..4547916 100644
--- a/pkg/kubernetes/resources.go
+++ b/pkg/kubernetes/resources.go
@@ -2,6 +2,7 @@ package kubernetes
 
 import (
 	"context"
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	"regexp"
 	"strings"
 
@@ -20,32 +21,28 @@ const (
 	AppKubernetesPartOf    = "app.kubernetes.io/part-of"
 )
 
-func (k *Kubernetes) ResourcesList(ctx context.Context, gvk *schema.GroupVersionKind, namespace string, labelSelector ...string) (string, error) {
+func (k *Kubernetes) ResourcesList(ctx context.Context, gvk *schema.GroupVersionKind, namespace string, labelSelector ...string) ([]unstructured.Unstructured, error) {
 	var selector string
 	if len(labelSelector) > 0 {
 		selector = labelSelector[0]
 	}
 	rl, err := k.resourcesList(ctx, gvk, namespace, selector)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
-	return marshal(rl.Items)
+	return rl.Items, nil
 }
 
-func (k *Kubernetes) ResourcesGet(ctx context.Context, gvk *schema.GroupVersionKind, namespace, name string) (string, error) {
+func (k *Kubernetes) ResourcesGet(ctx context.Context, gvk *schema.GroupVersionKind, namespace, name string) (*unstructured.Unstructured, error) {
 	gvr, err := k.resourceFor(gvk)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 	// If it's a namespaced resource and namespace wasn't provided, try to use the default configured one
 	if namespaced, nsErr := k.isNamespaced(gvk); nsErr == nil && namespaced {
 		namespace = k.NamespaceOrDefault(namespace)
 	}
-	rg, err := k.dynamicClient.Resource(*gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
-	if err != nil {
-		return "", err
-	}
-	return marshal(rg)
+	return k.dynamicClient.Resource(*gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
 }
 
 func (k *Kubernetes) ResourcesCreateOrUpdate(ctx context.Context, resource string) (string, error) {
@@ -112,7 +109,7 @@ func (k *Kubernetes) resourcesCreateOrUpdate(ctx context.Context, resources []*u
 			k.deferredDiscoveryRESTMapper.Reset()
 		}
 	}
-	marshalledYaml, err := marshal(resources)
+	marshalledYaml, err := output.MarshalYaml(resources)
 	if err != nil {
 		return "", err
 	}
diff --git a/pkg/mcp/mcp.go b/pkg/mcp/mcp.go
index 4e784cf..1e54bd9 100644
--- a/pkg/mcp/mcp.go
+++ b/pkg/mcp/mcp.go
@@ -3,6 +3,7 @@ package mcp
 import (
 	"context"
 	"github.com/manusa/kubernetes-mcp-server/pkg/kubernetes"
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	"github.com/manusa/kubernetes-mcp-server/pkg/version"
 	"github.com/mark3labs/mcp-go/mcp"
 	"github.com/mark3labs/mcp-go/server"
@@ -11,6 +12,7 @@ import (
 
 type Configuration struct {
 	Profile Profile
+	Output  output.Output
 	// When true, expose only tools annotated with readOnlyHint=true
 	ReadOnly bool
 	// When true, disable tools annotated with destructiveHint=true
diff --git a/pkg/mcp/namespaces.go b/pkg/mcp/namespaces.go
index c8452f5..3f6c171 100644
--- a/pkg/mcp/namespaces.go
+++ b/pkg/mcp/namespaces.go
@@ -37,15 +37,15 @@ func (s *Server) initNamespaces() []server.ServerTool {
 func (s *Server) namespacesList(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 	ret, err := s.k.Derived(ctx).NamespacesList(ctx)
 	if err != nil {
-		err = fmt.Errorf("failed to list namespaces: %v", err)
+		return NewTextResult("", fmt.Errorf("failed to list namespaces: %v", err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) projectsList(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 	ret, err := s.k.Derived(ctx).ProjectsList(ctx)
 	if err != nil {
-		err = fmt.Errorf("failed to list projects: %v", err)
+		return NewTextResult("", fmt.Errorf("failed to list projects: %v", err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
diff --git a/pkg/mcp/pods.go b/pkg/mcp/pods.go
index 346114c..a0bf779 100644
--- a/pkg/mcp/pods.go
+++ b/pkg/mcp/pods.go
@@ -114,7 +114,7 @@ func (s *Server) podsListInAllNamespaces(ctx context.Context, ctr mcp.CallToolRe
 	if err != nil {
 		return NewTextResult("", fmt.Errorf("failed to list pods in all namespaces: %v", err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) podsListInNamespace(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -131,7 +131,7 @@ func (s *Server) podsListInNamespace(ctx context.Context, ctr mcp.CallToolReques
 	if err != nil {
 		return NewTextResult("", fmt.Errorf("failed to list pods in namespace %s: %v", ns, err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) podsGet(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -147,7 +147,7 @@ func (s *Server) podsGet(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.Cal
 	if err != nil {
 		return NewTextResult("", fmt.Errorf("failed to get pod %s in namespace %s: %v", name, ns, err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) podsDelete(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
diff --git a/pkg/mcp/profiles.go b/pkg/mcp/profiles.go
index c7df82f..d795b43 100644
--- a/pkg/mcp/profiles.go
+++ b/pkg/mcp/profiles.go
@@ -5,18 +5,18 @@ import (
 	"slices"
 )
 
-var Profiles = []Profile{
-	&FullProfile{},
-}
-
-var ProfileNames []string
-
 type Profile interface {
 	GetName() string
 	GetDescription() string
 	GetTools(s *Server) []server.ServerTool
 }
 
+var Profiles = []Profile{
+	&FullProfile{},
+}
+
+var ProfileNames []string
+
 func ProfileFromString(name string) Profile {
 	for _, profile := range Profiles {
 		if profile.GetName() == name {
diff --git a/pkg/mcp/resources.go b/pkg/mcp/resources.go
index 8ebf728..8aeeff5 100644
--- a/pkg/mcp/resources.go
+++ b/pkg/mcp/resources.go
@@ -115,7 +115,7 @@ func (s *Server) resourcesList(ctx context.Context, ctr mcp.CallToolRequest) (*m
 	if err != nil {
 		return NewTextResult("", fmt.Errorf("failed to list resources: %v", err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) resourcesGet(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
@@ -135,7 +135,7 @@ func (s *Server) resourcesGet(ctx context.Context, ctr mcp.CallToolRequest) (*mc
 	if err != nil {
 		return NewTextResult("", fmt.Errorf("failed to get resource: %v", err)), nil
 	}
-	return NewTextResult(ret, err), nil
+	return NewTextResult(s.configuration.Output.PrintObj(ret)), nil
 }
 
 func (s *Server) resourcesCreateOrUpdate(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
diff --git a/pkg/output/output.go b/pkg/output/output.go
new file mode 100644
index 0000000..92c086c
--- /dev/null
+++ b/pkg/output/output.go
@@ -0,0 +1,64 @@
+package output
+
+import (
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"sigs.k8s.io/yaml"
+)
+
+type Output interface {
+	GetName() string
+	PrintObj(obj any) (string, error)
+}
+
+var Outputs = []Output{
+	&YamlOutput{},
+}
+
+var Names []string
+
+func FromString(name string) Output {
+	for _, output := range Outputs {
+		if output.GetName() == name {
+			return output
+		}
+	}
+	return nil
+}
+
+type YamlOutput struct{}
+
+func (p *YamlOutput) GetName() string {
+	return "yaml"
+}
+func (p *YamlOutput) PrintObj(obj any) (string, error) {
+	return MarshalYaml(obj)
+}
+
+func MarshalYaml(v any) (string, error) {
+	switch t := v.(type) {
+	case []unstructured.Unstructured:
+		for i := range t {
+			t[i].SetManagedFields(nil)
+		}
+	case []*unstructured.Unstructured:
+		for i := range t {
+			t[i].SetManagedFields(nil)
+		}
+	case unstructured.Unstructured:
+		t.SetManagedFields(nil)
+	case *unstructured.Unstructured:
+		t.SetManagedFields(nil)
+	}
+	ret, err := yaml.Marshal(v)
+	if err != nil {
+		return "", err
+	}
+	return string(ret), nil
+}
+
+func init() {
+	Names = make([]string, 0)
+	for _, output := range Outputs {
+		Names = append(Names, output.GetName())
+	}
+}



Test patch:
diff --git a/pkg/kubernetes-mcp-server/cmd/root_test.go b/pkg/kubernetes-mcp-server/cmd/root_test.go
index b1c2036..731732a 100644
--- a/pkg/kubernetes-mcp-server/cmd/root_test.go
+++ b/pkg/kubernetes-mcp-server/cmd/root_test.go
@@ -22,22 +22,51 @@ func captureOutput(f func() error) (string, error) {
 
 func TestVersion(t *testing.T) {
 	rootCmd.SetArgs([]string{"--version"})
+	rootCmd.ResetFlags()
+	flagInit()
 	version, err := captureOutput(rootCmd.Execute)
 	if version != "0.0.0\n" {
 		t.Fatalf("Expected version 0.0.0, got %s %v", version, err)
 	}
 }
 
-func TestDefaultProfile(t *testing.T) {
-	rootCmd.SetArgs([]string{"--version", "--log-level=1"})
-	out, err := captureOutput(rootCmd.Execute)
-	if !strings.Contains(out, "- Profile: full") {
-		t.Fatalf("Expected profile 'full', got %s %v", out, err)
-	}
+func TestProfile(t *testing.T) {
+	t.Run("default", func(t *testing.T) {
+		rootCmd.SetArgs([]string{"--version", "--log-level=1"})
+		rootCmd.ResetFlags()
+		flagInit()
+		out, err := captureOutput(rootCmd.Execute)
+		if !strings.Contains(out, "- Profile: full") {
+			t.Fatalf("Expected profile 'full', got %s %v", out, err)
+		}
+	})
+}
+
+func TestOutput(t *testing.T) {
+	t.Run("available", func(t *testing.T) {
+		rootCmd.SetArgs([]string{"--help"})
+		rootCmd.ResetFlags()
+		flagInit()
+		out, err := captureOutput(rootCmd.Execute)
+		if !strings.Contains(out, "Output format for resources (one of: yaml)") {
+			t.Fatalf("Expected all available outputs, got %s %v", out, err)
+		}
+	})
+	t.Run("default", func(t *testing.T) {
+		rootCmd.SetArgs([]string{"--version", "--log-level=1"})
+		rootCmd.ResetFlags()
+		flagInit()
+		out, err := captureOutput(rootCmd.Execute)
+		if !strings.Contains(out, "- Output: yaml") {
+			t.Fatalf("Expected output 'yaml', got %s %v", out, err)
+		}
+	})
 }
 
 func TestDefaultReadOnly(t *testing.T) {
 	rootCmd.SetArgs([]string{"--version", "--log-level=1"})
+	rootCmd.ResetFlags()
+	flagInit()
 	out, err := captureOutput(rootCmd.Execute)
 	if !strings.Contains(out, " - Read-only mode: false") {
 		t.Fatalf("Expected read-only mode false, got %s %v", out, err)
@@ -46,6 +75,8 @@ func TestDefaultReadOnly(t *testing.T) {
 
 func TestDefaultDisableDestructive(t *testing.T) {
 	rootCmd.SetArgs([]string{"--version", "--log-level=1"})
+	rootCmd.ResetFlags()
+	flagInit()
 	out, err := captureOutput(rootCmd.Execute)
 	if !strings.Contains(out, " - Disable destructive tools: false") {
 		t.Fatalf("Expected disable destructive false, got %s %v", out, err)
diff --git a/pkg/mcp/common_test.go b/pkg/mcp/common_test.go
index 7312ba9..f56799a 100644
--- a/pkg/mcp/common_test.go
+++ b/pkg/mcp/common_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/manusa/kubernetes-mcp-server/pkg/output"
 	"github.com/mark3labs/mcp-go/client"
 	"github.com/mark3labs/mcp-go/client/transport"
 	"github.com/mark3labs/mcp-go/mcp"
@@ -96,6 +97,7 @@ func TestMain(m *testing.M) {
 
 type mcpContext struct {
 	profile            Profile
+	output             output.Output
 	readOnly           bool
 	disableDestructive bool
 	clientOptions      []transport.ClientOption
@@ -117,11 +119,17 @@ func (c *mcpContext) beforeEach(t *testing.T) {
 	if c.profile == nil {
 		c.profile = &FullProfile{}
 	}
+	if c.output == nil {
+		c.output = &output.YamlOutput{}
+	}
 	if c.before != nil {
 		c.before(c)
 	}
 	if c.mcpServer, err = NewSever(Configuration{
-		Profile: c.profile, ReadOnly: c.readOnly, DisableDestructive: c.disableDestructive,
+		Profile:            c.profile,
+		Output:             c.output,
+		ReadOnly:           c.readOnly,
+		DisableDestructive: c.disableDestructive,
 	}); err != nil {
 		t.Fatal(err)
 		return
diff --git a/pkg/mcp/pods_test.go b/pkg/mcp/pods_test.go
index ffa501b..a19330d 100644
--- a/pkg/mcp/pods_test.go
+++ b/pkg/mcp/pods_test.go
@@ -21,11 +21,9 @@ func TestPodsListInAllNamespaces(t *testing.T) {
 		t.Run("pods_list returns pods list", func(t *testing.T) {
 			if err != nil {
 				t.Fatalf("call tool failed %v", err)
-				return
 			}
 			if toolResult.IsError {
 				t.Fatalf("call tool failed")
-				return
 			}
 		})
 		var decoded []unstructured.Unstructured
@@ -33,39 +31,32 @@ func TestPodsListInAllNamespaces(t *testing.T) {
 		t.Run("pods_list has yaml content", func(t *testing.T) {
 			if err != nil {
 				t.Fatalf("invalid tool result content %v", err)
-				return
 			}
 		})
 		t.Run("pods_list returns 3 items", func(t *testing.T) {
 			if len(decoded) != 3 {
 				t.Fatalf("invalid pods count, expected 3, got %v", len(decoded))
-				return
 			}
 		})
 		t.Run("pods_list returns pod in ns-1", func(t *testing.T) {
 			if decoded[1].GetName() != "a-pod-in-ns-1" {
 				t.Fatalf("invalid pod name, expected a-pod-in-ns-1, got %v", decoded[1].GetName())
-				return
 			}
 			if decoded[1].GetNamespace() != "ns-1" {
 				t.Fatalf("invalid pod namespace, expected ns-1, got %v", decoded[1].GetNamespace())
-				return
 			}
 		})
 		t.Run("pods_list returns pod in ns-2", func(t *testing.T) {
 			if decoded[2].GetName() != "a-pod-in-ns-2" {
 				t.Fatalf("invalid pod name, expected a-pod-in-ns-2, got %v", decoded[2].GetName())
-				return
 			}
 			if decoded[2].GetNamespace() != "ns-2" {
 				t.Fatalf("invalid pod namespace, expected ns-2, got %v", decoded[2].GetNamespace())
-				return
 			}
 		})
 		t.Run("pods_list omits managed fields", func(t *testing.T) {
 			if decoded[1].GetManagedFields() != nil {
 				t.Fatalf("managed fields should be omitted, got %v", decoded[0].GetManagedFields())
-				return
 			}
 		})
 	})