Files
openshift-mcp-server/pkg/mcp/helm.go
2025-07-22 14:22:19 +02:00

119 lines
4.6 KiB
Go

package mcp
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func (s *Server) initHelm() []server.ServerTool {
return []server.ServerTool{
{Tool: mcp.NewTool("helm_install",
mcp.WithDescription("Install a Helm chart in the current or provided namespace"),
mcp.WithString("chart", mcp.Description("Chart reference to install (for example: stable/grafana, oci://ghcr.io/nginxinc/charts/nginx-ingress)"), mcp.Required()),
mcp.WithObject("values", mcp.Description("Values to pass to the Helm chart (Optional)")),
mcp.WithString("name", mcp.Description("Name of the Helm release (Optional, random name if not provided)")),
mcp.WithString("namespace", mcp.Description("Namespace to install the Helm chart in (Optional, current namespace if not provided)")),
// Tool annotations
mcp.WithTitleAnnotation("Helm: Install"),
mcp.WithReadOnlyHintAnnotation(false),
mcp.WithDestructiveHintAnnotation(false),
mcp.WithIdempotentHintAnnotation(false), // TODO: consider replacing implementation with equivalent to: helm upgrade --install
mcp.WithOpenWorldHintAnnotation(true),
), Handler: s.helmInstall},
{Tool: mcp.NewTool("helm_list",
mcp.WithDescription("List all the Helm releases in the current or provided namespace (or in all namespaces if specified)"),
mcp.WithString("namespace", mcp.Description("Namespace to list Helm releases from (Optional, all namespaces if not provided)")),
mcp.WithBoolean("all_namespaces", mcp.Description("If true, lists all Helm releases in all namespaces ignoring the namespace argument (Optional)")),
// Tool annotations
mcp.WithTitleAnnotation("Helm: List"),
mcp.WithReadOnlyHintAnnotation(true),
mcp.WithDestructiveHintAnnotation(false),
mcp.WithOpenWorldHintAnnotation(true),
), Handler: s.helmList},
{Tool: mcp.NewTool("helm_uninstall",
mcp.WithDescription("Uninstall a Helm release in the current or provided namespace"),
mcp.WithString("name", mcp.Description("Name of the Helm release to uninstall"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("Namespace to uninstall the Helm release from (Optional, current namespace if not provided)")),
// Tool annotations
mcp.WithTitleAnnotation("Helm: Uninstall"),
mcp.WithReadOnlyHintAnnotation(false),
mcp.WithDestructiveHintAnnotation(true),
mcp.WithIdempotentHintAnnotation(true),
mcp.WithOpenWorldHintAnnotation(true),
), Handler: s.helmUninstall},
}
}
func (s *Server) helmInstall(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
var chart string
ok := false
if chart, ok = ctr.GetArguments()["chart"].(string); !ok {
return NewTextResult("", fmt.Errorf("failed to install helm chart, missing argument chart")), nil
}
values := map[string]interface{}{}
if v, ok := ctr.GetArguments()["values"].(map[string]interface{}); ok {
values = v
}
name := ""
if v, ok := ctr.GetArguments()["name"].(string); ok {
name = v
}
namespace := ""
if v, ok := ctr.GetArguments()["namespace"].(string); ok {
namespace = v
}
derived, err := s.k.Derived(ctx)
if err != nil {
return nil, err
}
ret, err := derived.NewHelm().Install(ctx, chart, values, name, namespace)
if err != nil {
return NewTextResult("", fmt.Errorf("failed to install helm chart '%s': %w", chart, err)), nil
}
return NewTextResult(ret, err), nil
}
func (s *Server) helmList(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
allNamespaces := false
if v, ok := ctr.GetArguments()["all_namespaces"].(bool); ok {
allNamespaces = v
}
namespace := ""
if v, ok := ctr.GetArguments()["namespace"].(string); ok {
namespace = v
}
derived, err := s.k.Derived(ctx)
if err != nil {
return nil, err
}
ret, err := derived.NewHelm().List(namespace, allNamespaces)
if err != nil {
return NewTextResult("", fmt.Errorf("failed to list helm releases in namespace '%s': %w", namespace, err)), nil
}
return NewTextResult(ret, err), nil
}
func (s *Server) helmUninstall(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.CallToolResult, error) {
var name string
ok := false
if name, ok = ctr.GetArguments()["name"].(string); !ok {
return NewTextResult("", fmt.Errorf("failed to uninstall helm chart, missing argument name")), nil
}
namespace := ""
if v, ok := ctr.GetArguments()["namespace"].(string); ok {
namespace = v
}
derived, err := s.k.Derived(ctx)
if err != nil {
return nil, err
}
ret, err := derived.NewHelm().Uninstall(name, namespace)
if err != nil {
return NewTextResult("", fmt.Errorf("failed to uninstall helm chart '%s': %w", name, err)), nil
}
return NewTextResult(ret, err), nil
}