diff --git a/internal/test/toolset_builder.go b/internal/test/toolset_builder.go new file mode 100644 index 000000000..9565b62c7 --- /dev/null +++ b/internal/test/toolset_builder.go @@ -0,0 +1,220 @@ +package test + +import ( + "encoding/json" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/mark3labs/mcp-go/mcp" +) + +// ToolsetBuilderOptions configures how to build the expected tool list for tests +type ToolsetBuilderOptions struct { + // Toolsets to include (e.g., "core", "config", "helm") + Toolsets []string + + // Environment flags + IsOpenShift bool + IsMultiCluster bool + + // MultiCluster configuration + Contexts []string + DefaultContext string + TargetParamName string // e.g., "context" for kubeconfig contexts +} + +// testMetadata contains test-specific metadata for conditional tool inclusion/modification +type testMetadata struct { + RequiresOpenShift bool `json:"requires_openshift,omitempty"` + RequiresMultiCluster bool `json:"requires_multicluster,omitempty"` + ClusterAware *bool `json:"cluster_aware,omitempty"` + TargetListProvider bool `json:"target_list_provider,omitempty"` +} + +// toolWithMetadata extends mcp.Tool with test metadata for conditional inclusion +type toolWithMetadata struct { + mcp.Tool + TestMetadata *testMetadata `json:"test_metadata,omitempty"` +} + +// BuildExpectedToolsJSON constructs the expected tool list JSON based on options +// This mirrors the runtime behavior of toolset registration, filtering, and mutation +// Returns a JSON string that can be compared with actual tools using JSONEq +func BuildExpectedToolsJSON(opts ToolsetBuilderOptions) string { + // Use runtime.Caller to find where this function was called from (the test file) + // Skip 1 frame to get the caller (the test function) + _, callerFile, _, _ := runtime.Caller(1) + testdataDir := filepath.Join(filepath.Dir(callerFile), "testdata") + + tools := buildExpectedTools(opts, testdataDir) + + // Marshal to JSON with indentation to match test.ReadFile format + jsonBytes := Must(json.MarshalIndent(tools, "", " ")) + return string(jsonBytes) +} + +// buildExpectedTools constructs the expected tool list based on options +func buildExpectedTools(opts ToolsetBuilderOptions, testdataDir string) []mcp.Tool { + // Set defaults + if opts.TargetParamName == "" { + opts.TargetParamName = "context" + } + + // Load and merge toolset JSONs + toolsWithMeta := loadToolsets(opts.Toolsets, testdataDir) + + // Apply filters + toolsWithMeta = filterTools(toolsWithMeta, opts) + + // Apply mutations and extract clean tools + tools := mutateTools(toolsWithMeta, opts) + + // Sort tools by name to match server output + sort.Slice(tools, func(i, j int) bool { + return tools[i].Name < tools[j].Name + }) + + return tools +} + +// loadToolsets loads and merges JSON files for the specified toolsets from the given testdata directory +func loadToolsets(toolsets []string, testdataDir string) []toolWithMetadata { + var allTools []toolWithMetadata + + for _, toolset := range toolsets { + filename := "toolsets-" + toolset + "-tools.json" + testdataPath := filepath.Join(testdataDir, filename) + + content := Must(os.ReadFile(testdataPath)) + + var tools []toolWithMetadata + Must(tools, json.Unmarshal(content, &tools)) + + allTools = append(allTools, tools...) + } + + return allTools +} + +// filterTools removes tools that don't match the environment conditions +func filterTools(tools []toolWithMetadata, opts ToolsetBuilderOptions) []toolWithMetadata { + var filtered []toolWithMetadata + + for _, tool := range tools { + meta := tool.TestMetadata + if meta == nil { + // No metadata means no conditions - always include + filtered = append(filtered, tool) + continue + } + + // Skip if requires OpenShift but not in OpenShift + if meta.RequiresOpenShift && !opts.IsOpenShift { + continue + } + + // Skip if requires multicluster but not in multicluster + if meta.RequiresMultiCluster && !opts.IsMultiCluster { + continue + } + + // Skip target list providers if only one target + // (mirrors ShouldIncludeTargetListTool filter) + if meta.TargetListProvider && len(opts.Contexts) <= 1 { + continue + } + + filtered = append(filtered, tool) + } + + return filtered +} + +// mutateTools applies transformations like adding context parameters and modifying descriptions +func mutateTools(toolsWithMeta []toolWithMetadata, opts ToolsetBuilderOptions) []mcp.Tool { + tools := make([]mcp.Tool, len(toolsWithMeta)) + + for i, toolMeta := range toolsWithMeta { + tool := toolMeta.Tool + + // Add context parameter for cluster-aware tools in multicluster mode + if opts.IsMultiCluster && isClusterAware(toolMeta) { + addContextParameter(&tool.InputSchema, opts.TargetParamName, opts.DefaultContext, opts.Contexts) + } + + // Add OpenShift-specific text to resource tool descriptions + if opts.IsOpenShift && isResourceTool(tool.Name) { + tool.Description = addOpenShiftToDescription(tool.Description) + } + + tools[i] = tool + } + + return tools +} + +// isResourceTool checks if a tool is one of the generic resource tools that get OpenShift descriptions +func isResourceTool(name string) bool { + return strings.HasPrefix(name, "resources_") +} + +// addOpenShiftToDescription adds OpenShift-specific resource types to tool descriptions +// Mirrors the logic in pkg/toolsets/core/resources.go initResources function +func addOpenShiftToDescription(description string) string { + // Replace the closing parenthesis with OpenShift route type + return strings.Replace(description, + "networking.k8s.io/v1 Ingress)", + "networking.k8s.io/v1 Ingress, route.openshift.io/v1 Route)", + 1) +} + +// isClusterAware checks if a tool should receive the context parameter +func isClusterAware(tool toolWithMetadata) bool { + // If explicitly set in metadata, use that value + if tool.TestMetadata != nil && tool.TestMetadata.ClusterAware != nil { + return *tool.TestMetadata.ClusterAware + } + + // Default to true (mirrors api.ServerTool.IsClusterAware) + return true +} + +// addContextParameter adds a context/cluster parameter to the tool's input schema (mutates in place) +// This mirrors the WithTargetParameter ToolMutator +func addContextParameter(schema *mcp.ToolInputSchema, paramName, defaultContext string, contexts []string) { + // Don't add if only one context + if len(contexts) <= 1 { + return + } + + // Ensure schema has properties map + if schema.Properties == nil { + schema.Properties = make(map[string]any) + } + + // Create the context property + contextProp := map[string]any{ + "type": "string", + "description": "Optional parameter selecting which " + paramName + + " to run the tool in. Defaults to " + defaultContext + " if not set", + } + + // Add enum if <= 5 contexts (mirrors maxTargetsInEnum constant) + if len(contexts) <= 5 { + // Sort contexts to ensure consistent enum ordering + sorted := make([]string, len(contexts)) + copy(sorted, contexts) + sort.Strings(sorted) + + enumValues := make([]any, len(sorted)) + for i, c := range sorted { + enumValues[i] = c + } + contextProp["enum"] = enumValues + } + + schema.Properties[paramName] = contextProp +} diff --git a/pkg/mcp/testdata/toolsets-config-tools.json b/pkg/mcp/testdata/toolsets-config-tools.json index c17674914..66959e84d 100644 --- a/pkg/mcp/testdata/toolsets-config-tools.json +++ b/pkg/mcp/testdata/toolsets-config-tools.json @@ -1,4 +1,23 @@ [ + { + "annotations": { + "title": "Configuration: Contexts List", + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false + }, + "description": "List all available context names and associated server urls from the kubeconfig file", + "inputSchema": { + "type": "object" + }, + "name": "configuration_contexts_list", + "test_metadata": { + "requires_multicluster": true, + "target_list_provider": true, + "cluster_aware": false + } + }, { "annotations": { "title": "Configuration: View", @@ -17,6 +36,9 @@ } } }, - "name": "configuration_view" + "name": "configuration_view", + "test_metadata": { + "cluster_aware": false + } } ] diff --git a/pkg/mcp/testdata/toolsets-core-tools.json b/pkg/mcp/testdata/toolsets-core-tools.json index 43680daec..827db13f5 100644 --- a/pkg/mcp/testdata/toolsets-core-tools.json +++ b/pkg/mcp/testdata/toolsets-core-tools.json @@ -285,6 +285,23 @@ }, "name": "pods_top" }, + { + "annotations": { + "title": "Projects: List", + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": false, + "openWorldHint": true + }, + "description": "List all the OpenShift projects in the current cluster", + "inputSchema": { + "type": "object" + }, + "name": "projects_list", + "test_metadata": { + "requires_openshift": true + } + }, { "annotations": { "title": "Resources: Create or Update", diff --git a/pkg/mcp/testdata/toolsets-full-tools-multicluster-enum.json b/pkg/mcp/testdata/toolsets-full-tools-multicluster-enum.json deleted file mode 100644 index 97af6fb5b..000000000 --- a/pkg/mcp/testdata/toolsets-full-tools-multicluster-enum.json +++ /dev/null @@ -1,680 +0,0 @@ -[ - { - "annotations": { - "title": "Configuration: Contexts List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": false - }, - "description": "List all available context names and associated server urls from the kubeconfig file", - "inputSchema": { - "type": "object" - }, - "name": "configuration_contexts_list" - }, - { - "annotations": { - "title": "Configuration: View", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the current Kubernetes configuration content as a kubeconfig YAML", - "inputSchema": { - "type": "object", - "properties": { - "minified": { - "description": "Return a minified version of the configuration. If set to true, keeps only the current-context and the relevant pieces of the configuration for that context. If set to false, all contexts, clusters, auth-infos, and users are returned in the configuration. (Optional, default true)", - "type": "boolean" - } - } - }, - "name": "configuration_view" - }, - { - "annotations": { - "title": "Events: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes events in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the events from. If not provided, will list events from all namespaces", - "type": "string" - } - } - }, - "name": "events_list" - }, - { - "annotations": { - "title": "Helm: Install", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Install a Helm chart in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "chart": { - "description": "Chart reference to install (for example: stable/grafana, oci://ghcr.io/nginxinc/charts/nginx-ingress)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Helm release (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to install the Helm chart in (Optional, current namespace if not provided)", - "type": "string" - }, - "values": { - "description": "Values to pass to the Helm chart (Optional)", - "type": "object" - } - }, - "required": [ - "chart" - ] - }, - "name": "helm_install" - }, - { - "annotations": { - "title": "Helm: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Helm releases in the current or provided namespace (or in all namespaces if specified)", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "description": "If true, lists all Helm releases in all namespaces ignoring the namespace argument (Optional)", - "type": "boolean" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "namespace": { - "description": "Namespace to list Helm releases from (Optional, all namespaces if not provided)", - "type": "string" - } - } - }, - "name": "helm_list" - }, - { - "annotations": { - "title": "Helm: Uninstall", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Uninstall a Helm release in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Helm release to uninstall", - "type": "string" - }, - "namespace": { - "description": "Namespace to uninstall the Helm release from (Optional, current namespace if not provided)", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "helm_uninstall" - }, - { - "annotations": { - "title": "Namespaces: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes namespaces in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - } - } - }, - "name": "namespaces_list" - }, - { - "annotations": { - "title": "Pods: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Pod to delete", - "type": "string" - }, - "namespace": { - "description": "Namespace to delete the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_delete" - }, - { - "annotations": { - "title": "Pods: Exec", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Execute a command in a Kubernetes Pod in the current or provided namespace with the provided name and command", - "inputSchema": { - "type": "object", - "properties": { - "command": { - "description": "Command to execute in the Pod container. The first item is the command to be run, and the rest are the arguments to that command. Example: [\"ls\", \"-l\", \"/tmp\"]", - "items": { - "type": "string" - }, - "type": "array" - }, - "container": { - "description": "Name of the Pod container where the command will be executed (Optional)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Pod where the command will be executed", - "type": "string" - }, - "namespace": { - "description": "Namespace of the Pod where the command will be executed", - "type": "string" - } - }, - "required": [ - "name", - "command" - ] - }, - "name": "pods_exec" - }, - { - "annotations": { - "title": "Pods: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Pod", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_get" - }, - { - "annotations": { - "title": "Pods: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - } - } - }, - "name": "pods_list" - }, - { - "annotations": { - "title": "Pods: List in Namespace", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the specified namespace in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Namespace to list pods from", - "type": "string" - } - }, - "required": [ - "namespace" - ] - }, - "name": "pods_list_in_namespace" - }, - { - "annotations": { - "title": "Pods: Log", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the logs of a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "container": { - "description": "Name of the Pod container to get the logs from (Optional)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the logs from", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod logs from", - "type": "string" - }, - "previous": { - "description": "Return previous terminated container logs (Optional)", - "type": "boolean" - }, - "tail": { - "default": 100, - "description": "Number of lines to retrieve from the end of the logs (Optional, default: 100)", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_log" - }, - { - "annotations": { - "title": "Pods: Run", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Run a Kubernetes Pod in the current or provided namespace with the provided container image and optional name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "image": { - "description": "Container Image to run in the Pod", - "type": "string" - }, - "name": { - "description": "Name of the Pod (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to run the Pod in", - "type": "string" - }, - "port": { - "description": "TCP/IP port to expose from the Pod container (Optional, no port exposed if not provided)", - "type": "number" - } - }, - "required": [ - "image" - ] - }, - "name": "pods_run" - }, - { - "annotations": { - "title": "Pods: Top", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "List the resource consumption (CPU and memory) as recorded by the Kubernetes Metrics Server for the specified Kubernetes Pods in the all namespaces, the provided namespace, or the current namespace", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "default": true, - "description": "If true, list the resource consumption for all Pods in all namespaces. If false, list the resource consumption for Pods in the provided namespace or the current namespace", - "type": "boolean" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "label_selector": { - "description": "Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label (Optional, only applicable when name is not provided)", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the resource consumption from (Optional, all Pods in the namespace if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pods resource consumption from (Optional, current namespace if not provided and all_namespaces is false)", - "type": "string" - } - } - }, - "name": "pods_top" - }, - { - "annotations": { - "title": "Resources: Create or Update", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Create or update a Kubernetes resource in the current cluster by providing a YAML or JSON representation of the resource\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "resource": { - "description": "A JSON or YAML containing a representation of the Kubernetes resource. Should include top-level fields such as apiVersion,kind,metadata, and spec", - "type": "string" - } - }, - "required": [ - "resource" - ] - }, - "name": "resources_create_or_update" - }, - { - "annotations": { - "title": "Resources: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to delete the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will delete resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_delete" - }, - { - "annotations": { - "title": "Resources: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will get resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_get" - }, - { - "annotations": { - "title": "Resources: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List Kubernetes resources and objects in the current cluster by providing their apiVersion and kind and optionally the namespace and label selector\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resources (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "enum": [ - "extra-cluster", - "fake-context" - ], - "type": "string" - }, - "kind": { - "description": "kind of the resources (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resources from (ignored in case of cluster scoped resources). If not provided, will list resources from all namespaces", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind" - ] - }, - "name": "resources_list" - } -] diff --git a/pkg/mcp/testdata/toolsets-full-tools-multicluster.json b/pkg/mcp/testdata/toolsets-full-tools-multicluster.json deleted file mode 100644 index 861a1b5ab..000000000 --- a/pkg/mcp/testdata/toolsets-full-tools-multicluster.json +++ /dev/null @@ -1,612 +0,0 @@ -[ - { - "annotations": { - "title": "Configuration: Contexts List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": false - }, - "description": "List all available context names and associated server urls from the kubeconfig file", - "inputSchema": { - "type": "object" - }, - "name": "configuration_contexts_list" - }, - { - "annotations": { - "title": "Configuration: View", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the current Kubernetes configuration content as a kubeconfig YAML", - "inputSchema": { - "type": "object", - "properties": { - "minified": { - "description": "Return a minified version of the configuration. If set to true, keeps only the current-context and the relevant pieces of the configuration for that context. If set to false, all contexts, clusters, auth-infos, and users are returned in the configuration. (Optional, default true)", - "type": "boolean" - } - } - }, - "name": "configuration_view" - }, - { - "annotations": { - "title": "Events: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes events in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the events from. If not provided, will list events from all namespaces", - "type": "string" - } - } - }, - "name": "events_list" - }, - { - "annotations": { - "title": "Helm: Install", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Install a Helm chart in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "chart": { - "description": "Chart reference to install (for example: stable/grafana, oci://ghcr.io/nginxinc/charts/nginx-ingress)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Helm release (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to install the Helm chart in (Optional, current namespace if not provided)", - "type": "string" - }, - "values": { - "description": "Values to pass to the Helm chart (Optional)", - "type": "object" - } - }, - "required": [ - "chart" - ] - }, - "name": "helm_install" - }, - { - "annotations": { - "title": "Helm: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Helm releases in the current or provided namespace (or in all namespaces if specified)", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "description": "If true, lists all Helm releases in all namespaces ignoring the namespace argument (Optional)", - "type": "boolean" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "namespace": { - "description": "Namespace to list Helm releases from (Optional, all namespaces if not provided)", - "type": "string" - } - } - }, - "name": "helm_list" - }, - { - "annotations": { - "title": "Helm: Uninstall", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Uninstall a Helm release in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Helm release to uninstall", - "type": "string" - }, - "namespace": { - "description": "Namespace to uninstall the Helm release from (Optional, current namespace if not provided)", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "helm_uninstall" - }, - { - "annotations": { - "title": "Namespaces: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes namespaces in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - } - } - }, - "name": "namespaces_list" - }, - { - "annotations": { - "title": "Pods: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Pod to delete", - "type": "string" - }, - "namespace": { - "description": "Namespace to delete the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_delete" - }, - { - "annotations": { - "title": "Pods: Exec", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Execute a command in a Kubernetes Pod in the current or provided namespace with the provided name and command", - "inputSchema": { - "type": "object", - "properties": { - "command": { - "description": "Command to execute in the Pod container. The first item is the command to be run, and the rest are the arguments to that command. Example: [\"ls\", \"-l\", \"/tmp\"]", - "items": { - "type": "string" - }, - "type": "array" - }, - "container": { - "description": "Name of the Pod container where the command will be executed (Optional)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Pod where the command will be executed", - "type": "string" - }, - "namespace": { - "description": "Namespace of the Pod where the command will be executed", - "type": "string" - } - }, - "required": [ - "name", - "command" - ] - }, - "name": "pods_exec" - }, - { - "annotations": { - "title": "Pods: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Pod", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_get" - }, - { - "annotations": { - "title": "Pods: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - } - } - }, - "name": "pods_list" - }, - { - "annotations": { - "title": "Pods: List in Namespace", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the specified namespace in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Namespace to list pods from", - "type": "string" - } - }, - "required": [ - "namespace" - ] - }, - "name": "pods_list_in_namespace" - }, - { - "annotations": { - "title": "Pods: Log", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the logs of a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "container": { - "description": "Name of the Pod container to get the logs from (Optional)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the logs from", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod logs from", - "type": "string" - }, - "previous": { - "description": "Return previous terminated container logs (Optional)", - "type": "boolean" - }, - "tail": { - "default": 100, - "description": "Number of lines to retrieve from the end of the logs (Optional, default: 100)", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_log" - }, - { - "annotations": { - "title": "Pods: Run", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Run a Kubernetes Pod in the current or provided namespace with the provided container image and optional name", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "image": { - "description": "Container Image to run in the Pod", - "type": "string" - }, - "name": { - "description": "Name of the Pod (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to run the Pod in", - "type": "string" - }, - "port": { - "description": "TCP/IP port to expose from the Pod container (Optional, no port exposed if not provided)", - "type": "number" - } - }, - "required": [ - "image" - ] - }, - "name": "pods_run" - }, - { - "annotations": { - "title": "Pods: Top", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "List the resource consumption (CPU and memory) as recorded by the Kubernetes Metrics Server for the specified Kubernetes Pods in the all namespaces, the provided namespace, or the current namespace", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "default": true, - "description": "If true, list the resource consumption for all Pods in all namespaces. If false, list the resource consumption for Pods in the provided namespace or the current namespace", - "type": "boolean" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "label_selector": { - "description": "Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label (Optional, only applicable when name is not provided)", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the resource consumption from (Optional, all Pods in the namespace if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pods resource consumption from (Optional, current namespace if not provided and all_namespaces is false)", - "type": "string" - } - } - }, - "name": "pods_top" - }, - { - "annotations": { - "title": "Resources: Create or Update", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Create or update a Kubernetes resource in the current cluster by providing a YAML or JSON representation of the resource\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "resource": { - "description": "A JSON or YAML containing a representation of the Kubernetes resource. Should include top-level fields such as apiVersion,kind,metadata, and spec", - "type": "string" - } - }, - "required": [ - "resource" - ] - }, - "name": "resources_create_or_update" - }, - { - "annotations": { - "title": "Resources: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to delete the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will delete resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_delete" - }, - { - "annotations": { - "title": "Resources: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will get resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_get" - }, - { - "annotations": { - "title": "Resources: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List Kubernetes resources and objects in the current cluster by providing their apiVersion and kind and optionally the namespace and label selector\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resources (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "context": { - "description": "Optional parameter selecting which context to run the tool in. Defaults to fake-context if not set", - "type": "string" - }, - "kind": { - "description": "kind of the resources (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resources from (ignored in case of cluster scoped resources). If not provided, will list resources from all namespaces", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind" - ] - }, - "name": "resources_list" - } -] diff --git a/pkg/mcp/testdata/toolsets-full-tools-openshift.json b/pkg/mcp/testdata/toolsets-full-tools-openshift.json deleted file mode 100644 index b50189454..000000000 --- a/pkg/mcp/testdata/toolsets-full-tools-openshift.json +++ /dev/null @@ -1,542 +0,0 @@ -[ - { - "annotations": { - "title": "Configuration: View", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the current Kubernetes configuration content as a kubeconfig YAML", - "inputSchema": { - "type": "object", - "properties": { - "minified": { - "description": "Return a minified version of the configuration. If set to true, keeps only the current-context and the relevant pieces of the configuration for that context. If set to false, all contexts, clusters, auth-infos, and users are returned in the configuration. (Optional, default true)", - "type": "boolean" - } - } - }, - "name": "configuration_view" - }, - { - "annotations": { - "title": "Events: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes events in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "namespace": { - "description": "Optional Namespace to retrieve the events from. If not provided, will list events from all namespaces", - "type": "string" - } - } - }, - "name": "events_list" - }, - { - "annotations": { - "title": "Helm: Install", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Install a Helm chart in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "chart": { - "description": "Chart reference to install (for example: stable/grafana, oci://ghcr.io/nginxinc/charts/nginx-ingress)", - "type": "string" - }, - "name": { - "description": "Name of the Helm release (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to install the Helm chart in (Optional, current namespace if not provided)", - "type": "string" - }, - "values": { - "description": "Values to pass to the Helm chart (Optional)", - "type": "object" - } - }, - "required": [ - "chart" - ] - }, - "name": "helm_install" - }, - { - "annotations": { - "title": "Helm: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Helm releases in the current or provided namespace (or in all namespaces if specified)", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "description": "If true, lists all Helm releases in all namespaces ignoring the namespace argument (Optional)", - "type": "boolean" - }, - "namespace": { - "description": "Namespace to list Helm releases from (Optional, all namespaces if not provided)", - "type": "string" - } - } - }, - "name": "helm_list" - }, - { - "annotations": { - "title": "Helm: Uninstall", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Uninstall a Helm release in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Helm release to uninstall", - "type": "string" - }, - "namespace": { - "description": "Namespace to uninstall the Helm release from (Optional, current namespace if not provided)", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "helm_uninstall" - }, - { - "annotations": { - "title": "Namespaces: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes namespaces in the current cluster", - "inputSchema": { - "type": "object" - }, - "name": "namespaces_list" - }, - { - "annotations": { - "title": "Pods: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Pod to delete", - "type": "string" - }, - "namespace": { - "description": "Namespace to delete the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_delete" - }, - { - "annotations": { - "title": "Pods: Exec", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Execute a command in a Kubernetes Pod in the current or provided namespace with the provided name and command", - "inputSchema": { - "type": "object", - "properties": { - "command": { - "description": "Command to execute in the Pod container. The first item is the command to be run, and the rest are the arguments to that command. Example: [\"ls\", \"-l\", \"/tmp\"]", - "items": { - "type": "string" - }, - "type": "array" - }, - "container": { - "description": "Name of the Pod container where the command will be executed (Optional)", - "type": "string" - }, - "name": { - "description": "Name of the Pod where the command will be executed", - "type": "string" - }, - "namespace": { - "description": "Namespace of the Pod where the command will be executed", - "type": "string" - } - }, - "required": [ - "name", - "command" - ] - }, - "name": "pods_exec" - }, - { - "annotations": { - "title": "Pods: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Pod", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_get" - }, - { - "annotations": { - "title": "Pods: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - } - } - }, - "name": "pods_list" - }, - { - "annotations": { - "title": "Pods: List in Namespace", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the specified namespace in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Namespace to list pods from", - "type": "string" - } - }, - "required": [ - "namespace" - ] - }, - "name": "pods_list_in_namespace" - }, - { - "annotations": { - "title": "Pods: Log", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the logs of a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "container": { - "description": "Name of the Pod container to get the logs from (Optional)", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the logs from", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod logs from", - "type": "string" - }, - "previous": { - "description": "Return previous terminated container logs (Optional)", - "type": "boolean" - }, - "tail": { - "default": 100, - "description": "Number of lines to retrieve from the end of the logs (Optional, default: 100)", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_log" - }, - { - "annotations": { - "title": "Pods: Run", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Run a Kubernetes Pod in the current or provided namespace with the provided container image and optional name", - "inputSchema": { - "type": "object", - "properties": { - "image": { - "description": "Container Image to run in the Pod", - "type": "string" - }, - "name": { - "description": "Name of the Pod (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to run the Pod in", - "type": "string" - }, - "port": { - "description": "TCP/IP port to expose from the Pod container (Optional, no port exposed if not provided)", - "type": "number" - } - }, - "required": [ - "image" - ] - }, - "name": "pods_run" - }, - { - "annotations": { - "title": "Pods: Top", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "List the resource consumption (CPU and memory) as recorded by the Kubernetes Metrics Server for the specified Kubernetes Pods in the all namespaces, the provided namespace, or the current namespace", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "default": true, - "description": "If true, list the resource consumption for all Pods in all namespaces. If false, list the resource consumption for Pods in the provided namespace or the current namespace", - "type": "boolean" - }, - "label_selector": { - "description": "Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label (Optional, only applicable when name is not provided)", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the resource consumption from (Optional, all Pods in the namespace if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pods resource consumption from (Optional, current namespace if not provided and all_namespaces is false)", - "type": "string" - } - } - }, - "name": "pods_top" - }, - { - "annotations": { - "title": "Projects: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the OpenShift projects in the current cluster", - "inputSchema": { - "type": "object" - }, - "name": "projects_list" - }, - { - "annotations": { - "title": "Resources: Create or Update", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Create or update a Kubernetes resource in the current cluster by providing a YAML or JSON representation of the resource\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress, route.openshift.io/v1 Route)", - "inputSchema": { - "type": "object", - "properties": { - "resource": { - "description": "A JSON or YAML containing a representation of the Kubernetes resource. Should include top-level fields such as apiVersion,kind,metadata, and spec", - "type": "string" - } - }, - "required": [ - "resource" - ] - }, - "name": "resources_create_or_update" - }, - { - "annotations": { - "title": "Resources: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress, route.openshift.io/v1 Route)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to delete the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will delete resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_delete" - }, - { - "annotations": { - "title": "Resources: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress, route.openshift.io/v1 Route)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will get resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_get" - }, - { - "annotations": { - "title": "Resources: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List Kubernetes resources and objects in the current cluster by providing their apiVersion and kind and optionally the namespace and label selector\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress, route.openshift.io/v1 Route)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resources (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resources (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resources from (ignored in case of cluster scoped resources). If not provided, will list resources from all namespaces", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind" - ] - }, - "name": "resources_list" - } -] diff --git a/pkg/mcp/testdata/toolsets-full-tools.json b/pkg/mcp/testdata/toolsets-full-tools.json deleted file mode 100644 index 7b9f471dd..000000000 --- a/pkg/mcp/testdata/toolsets-full-tools.json +++ /dev/null @@ -1,528 +0,0 @@ -[ - { - "annotations": { - "title": "Configuration: View", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the current Kubernetes configuration content as a kubeconfig YAML", - "inputSchema": { - "type": "object", - "properties": { - "minified": { - "description": "Return a minified version of the configuration. If set to true, keeps only the current-context and the relevant pieces of the configuration for that context. If set to false, all contexts, clusters, auth-infos, and users are returned in the configuration. (Optional, default true)", - "type": "boolean" - } - } - }, - "name": "configuration_view" - }, - { - "annotations": { - "title": "Events: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes events in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "namespace": { - "description": "Optional Namespace to retrieve the events from. If not provided, will list events from all namespaces", - "type": "string" - } - } - }, - "name": "events_list" - }, - { - "annotations": { - "title": "Helm: Install", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Install a Helm chart in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "chart": { - "description": "Chart reference to install (for example: stable/grafana, oci://ghcr.io/nginxinc/charts/nginx-ingress)", - "type": "string" - }, - "name": { - "description": "Name of the Helm release (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to install the Helm chart in (Optional, current namespace if not provided)", - "type": "string" - }, - "values": { - "description": "Values to pass to the Helm chart (Optional)", - "type": "object" - } - }, - "required": [ - "chart" - ] - }, - "name": "helm_install" - }, - { - "annotations": { - "title": "Helm: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Helm releases in the current or provided namespace (or in all namespaces if specified)", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "description": "If true, lists all Helm releases in all namespaces ignoring the namespace argument (Optional)", - "type": "boolean" - }, - "namespace": { - "description": "Namespace to list Helm releases from (Optional, all namespaces if not provided)", - "type": "string" - } - } - }, - "name": "helm_list" - }, - { - "annotations": { - "title": "Helm: Uninstall", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Uninstall a Helm release in the current or provided namespace", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Helm release to uninstall", - "type": "string" - }, - "namespace": { - "description": "Namespace to uninstall the Helm release from (Optional, current namespace if not provided)", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "helm_uninstall" - }, - { - "annotations": { - "title": "Namespaces: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes namespaces in the current cluster", - "inputSchema": { - "type": "object" - }, - "name": "namespaces_list" - }, - { - "annotations": { - "title": "Pods: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Pod to delete", - "type": "string" - }, - "namespace": { - "description": "Namespace to delete the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_delete" - }, - { - "annotations": { - "title": "Pods: Exec", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Execute a command in a Kubernetes Pod in the current or provided namespace with the provided name and command", - "inputSchema": { - "type": "object", - "properties": { - "command": { - "description": "Command to execute in the Pod container. The first item is the command to be run, and the rest are the arguments to that command. Example: [\"ls\", \"-l\", \"/tmp\"]", - "items": { - "type": "string" - }, - "type": "array" - }, - "container": { - "description": "Name of the Pod container where the command will be executed (Optional)", - "type": "string" - }, - "name": { - "description": "Name of the Pod where the command will be executed", - "type": "string" - }, - "namespace": { - "description": "Namespace of the Pod where the command will be executed", - "type": "string" - } - }, - "required": [ - "name", - "command" - ] - }, - "name": "pods_exec" - }, - { - "annotations": { - "title": "Pods: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "name": { - "description": "Name of the Pod", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod from", - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_get" - }, - { - "annotations": { - "title": "Pods: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the current cluster from all namespaces", - "inputSchema": { - "type": "object", - "properties": { - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - } - } - }, - "name": "pods_list" - }, - { - "annotations": { - "title": "Pods: List in Namespace", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List all the Kubernetes pods in the specified namespace in the current cluster", - "inputSchema": { - "type": "object", - "properties": { - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Namespace to list pods from", - "type": "string" - } - }, - "required": [ - "namespace" - ] - }, - "name": "pods_list_in_namespace" - }, - { - "annotations": { - "title": "Pods: Log", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get the logs of a Kubernetes Pod in the current or provided namespace with the provided name", - "inputSchema": { - "type": "object", - "properties": { - "container": { - "description": "Name of the Pod container to get the logs from (Optional)", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the logs from", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pod logs from", - "type": "string" - }, - "previous": { - "description": "Return previous terminated container logs (Optional)", - "type": "boolean" - }, - "tail": { - "default": 100, - "description": "Number of lines to retrieve from the end of the logs (Optional, default: 100)", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "name" - ] - }, - "name": "pods_log" - }, - { - "annotations": { - "title": "Pods: Run", - "readOnlyHint": false, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Run a Kubernetes Pod in the current or provided namespace with the provided container image and optional name", - "inputSchema": { - "type": "object", - "properties": { - "image": { - "description": "Container Image to run in the Pod", - "type": "string" - }, - "name": { - "description": "Name of the Pod (Optional, random name if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to run the Pod in", - "type": "string" - }, - "port": { - "description": "TCP/IP port to expose from the Pod container (Optional, no port exposed if not provided)", - "type": "number" - } - }, - "required": [ - "image" - ] - }, - "name": "pods_run" - }, - { - "annotations": { - "title": "Pods: Top", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "List the resource consumption (CPU and memory) as recorded by the Kubernetes Metrics Server for the specified Kubernetes Pods in the all namespaces, the provided namespace, or the current namespace", - "inputSchema": { - "type": "object", - "properties": { - "all_namespaces": { - "default": true, - "description": "If true, list the resource consumption for all Pods in all namespaces. If false, list the resource consumption for Pods in the provided namespace or the current namespace", - "type": "boolean" - }, - "label_selector": { - "description": "Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label (Optional, only applicable when name is not provided)", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "name": { - "description": "Name of the Pod to get the resource consumption from (Optional, all Pods in the namespace if not provided)", - "type": "string" - }, - "namespace": { - "description": "Namespace to get the Pods resource consumption from (Optional, current namespace if not provided and all_namespaces is false)", - "type": "string" - } - } - }, - "name": "pods_top" - }, - { - "annotations": { - "title": "Resources: Create or Update", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Create or update a Kubernetes resource in the current cluster by providing a YAML or JSON representation of the resource\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "resource": { - "description": "A JSON or YAML containing a representation of the Kubernetes resource. Should include top-level fields such as apiVersion,kind,metadata, and spec", - "type": "string" - } - }, - "required": [ - "resource" - ] - }, - "name": "resources_create_or_update" - }, - { - "annotations": { - "title": "Resources: Delete", - "readOnlyHint": false, - "destructiveHint": true, - "idempotentHint": true, - "openWorldHint": true - }, - "description": "Delete a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to delete the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will delete resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_delete" - }, - { - "annotations": { - "title": "Resources: Get", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "Get a Kubernetes resource in the current cluster by providing its apiVersion, kind, optionally the namespace, and its name\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resource (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resource (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "name": { - "description": "Name of the resource", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resource from (ignored in case of cluster scoped resources). If not provided, will get resource from configured namespace", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name" - ] - }, - "name": "resources_get" - }, - { - "annotations": { - "title": "Resources: List", - "readOnlyHint": true, - "destructiveHint": false, - "idempotentHint": false, - "openWorldHint": true - }, - "description": "List Kubernetes resources and objects in the current cluster by providing their apiVersion and kind and optionally the namespace and label selector\n(common apiVersion and kind include: v1 Pod, v1 Service, v1 Node, apps/v1 Deployment, networking.k8s.io/v1 Ingress)", - "inputSchema": { - "type": "object", - "properties": { - "apiVersion": { - "description": "apiVersion of the resources (examples of valid apiVersion are: v1, apps/v1, networking.k8s.io/v1)", - "type": "string" - }, - "kind": { - "description": "kind of the resources (examples of valid kind are: Pod, Service, Deployment, Ingress)", - "type": "string" - }, - "labelSelector": { - "description": "Optional Kubernetes label selector (e.g. 'app=myapp,env=prod' or 'app in (myapp,yourapp)'), use this option when you want to filter the pods by label", - "pattern": "([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]", - "type": "string" - }, - "namespace": { - "description": "Optional Namespace to retrieve the namespaced resources from (ignored in case of cluster scoped resources). If not provided, will list resources from all namespaces", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind" - ] - }, - "name": "resources_list" - } -] diff --git a/pkg/mcp/toolsets_test.go b/pkg/mcp/toolsets_test.go index 527b1e22e..31ce7d383 100644 --- a/pkg/mcp/toolsets_test.go +++ b/pkg/mcp/toolsets_test.go @@ -73,7 +73,9 @@ func (s *ToolsetsSuite) TestDefaultToolsetsTools() { s.NoError(err, "Expected no error from ListTools") }) s.Run("ListTools returns correct Tool metadata", func() { - expectedMetadata := test.ReadFile("testdata", "toolsets-full-tools.json") + expectedMetadata := test.BuildExpectedToolsJSON(test.ToolsetBuilderOptions{ + Toolsets: []string{"core", "config", "helm"}, + }) metadata, err := json.MarshalIndent(tools.Tools, "", " ") s.Require().NoErrorf(err, "failed to marshal tools metadata: %v", err) s.JSONEq(expectedMetadata, string(metadata), "tools metadata does not match expected") @@ -91,7 +93,10 @@ func (s *ToolsetsSuite) TestDefaultToolsetsToolsInOpenShift() { s.NoError(err, "Expected no error from ListTools") }) s.Run("ListTools returns correct Tool metadata", func() { - expectedMetadata := test.ReadFile("testdata", "toolsets-full-tools-openshift.json") + expectedMetadata := test.BuildExpectedToolsJSON(test.ToolsetBuilderOptions{ + Toolsets: []string{"core", "config", "helm"}, + IsOpenShift: true, + }) metadata, err := json.MarshalIndent(tools.Tools, "", " ") s.Require().NoErrorf(err, "failed to marshal tools metadata: %v", err) s.JSONEq(expectedMetadata, string(metadata), "tools metadata does not match expected") @@ -114,7 +119,17 @@ func (s *ToolsetsSuite) TestDefaultToolsetsToolsInMultiCluster() { s.NoError(err, "Expected no error from ListTools") }) s.Run("ListTools returns correct Tool metadata", func() { - expectedMetadata := test.ReadFile("testdata", "toolsets-full-tools-multicluster.json") + // Extract context names from kubeconfig + contexts := make([]string, 0, len(kubeconfig.Contexts)) + for name := range kubeconfig.Contexts { + contexts = append(contexts, name) + } + expectedMetadata := test.BuildExpectedToolsJSON(test.ToolsetBuilderOptions{ + Toolsets: []string{"core", "config", "helm"}, + IsMultiCluster: true, + Contexts: contexts, + DefaultContext: kubeconfig.CurrentContext, + }) metadata, err := json.MarshalIndent(tools.Tools, "", " ") s.Require().NoErrorf(err, "failed to marshal tools metadata: %v", err) s.JSONEq(expectedMetadata, string(metadata), "tools metadata does not match expected") @@ -135,7 +150,17 @@ func (s *ToolsetsSuite) TestDefaultToolsetsToolsInMultiClusterEnum() { s.NoError(err, "Expected no error from ListTools") }) s.Run("ListTools returns correct Tool metadata", func() { - expectedMetadata := test.ReadFile("testdata", "toolsets-full-tools-multicluster-enum.json") + // Extract context names from kubeconfig + contexts := make([]string, 0, len(kubeconfig.Contexts)) + for name := range kubeconfig.Contexts { + contexts = append(contexts, name) + } + expectedMetadata := test.BuildExpectedToolsJSON(test.ToolsetBuilderOptions{ + Toolsets: []string{"core", "config", "helm"}, + IsMultiCluster: true, + Contexts: contexts, + DefaultContext: kubeconfig.CurrentContext, + }) metadata, err := json.MarshalIndent(tools.Tools, "", " ") s.Require().NoErrorf(err, "failed to marshal tools metadata: %v", err) s.JSONEq(expectedMetadata, string(metadata), "tools metadata does not match expected") @@ -161,7 +186,9 @@ func (s *ToolsetsSuite) TestGranularToolsetsTools() { s.NoError(err, "Expected no error from ListTools") }) s.Run("ListTools returns correct Tool metadata", func() { - expectedMetadata := test.ReadFile("testdata", "toolsets-"+testCase.GetName()+"-tools.json") + expectedMetadata := test.BuildExpectedToolsJSON(test.ToolsetBuilderOptions{ + Toolsets: []string{testCase.GetName()}, + }) metadata, err := json.MarshalIndent(tools.Tools, "", " ") s.Require().NoErrorf(err, "failed to marshal tools metadata: %v", err) s.JSONEq(expectedMetadata, string(metadata), "tools metadata does not match expected")