diff --git a/README.md b/README.md index b39db03..05c2416 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,33 @@ Configure your MCP Cyclops server: | `get_template_schema` | Returns JSON schema for the given template. Needs to be checked before calling `create_module` tool | | `get_template_store` | Fetch Template Store by Name | | `list_template_store` | List Template Stores from cluster | + +## Configuration + +You can configure Cyclops MCP server via env variables. Below is an example of adding the configuration for specifying the kubeconfig file the Cyclops MCP server should use when managing your Cyclops applications. + +```json +{ + "mcpServers": { + "mcp-cyclops": { + "command": "mcp-cyclops", + "env": { + "KUBECONFIG": "/path/to/your/kubeconfig" + } + } + } +} + +``` + +### Environment variables + +Below is the list of environment variables used for configuring your Cyclops MCP server: + +| Env var | Description | +|-----------------------------------|-----------------------------------------------------------------------------------------| +| `KUBECONFIG` | Path to kubeconfig file (optional, defaults to in-cluster config or $HOME/.kube/config) | +| `CYCLOPS_KUBE_CONTEXT` | Kubernetes context to use (optional) | +| `CYCLOPS_MODULE_NAMESPACE` | Namespace where modules are stored | +| `CYCLOPS_HELM_RELEASE_NAMESPACE` | Namespace for Helm releases | +| `CYCLOPS_MODULE_TARGET_NAMESPACE` | Target namespace for modules | diff --git a/cmd/mcp-cyclops/main.go b/cmd/mcp-cyclops/main.go index 8fe7000..584d480 100644 --- a/cmd/mcp-cyclops/main.go +++ b/cmd/mcp-cyclops/main.go @@ -3,6 +3,7 @@ package main import ( "log" "os" + "path/filepath" "github.com/mark3labs/mcp-go/server" @@ -18,22 +19,37 @@ import ( "github.com/cyclops-ui/mcp-cyclops/internal/templatestores" ) +type Config struct { + kubeconfigPath string + kubeContext string + moduleNamespace string + helmReleaseNamespace string + moduleTargetNamespace string +} + func main() { + config := loadConfig() + s := server.NewMCPServer( "Cyclops", - "1.0.0", + "0.0.1", server.WithResourceCapabilities(true, true), server.WithLogging(), ) - k8sClient, err := k8sclient.New( - "cyclops", - "", - "", + k8sClient, err := k8sclient.NewWithConfig( + k8sclient.ClientConfig{ + KubeconfigPath: config.kubeconfigPath, + Context: config.kubeContext, + ModuleNamespace: config.moduleNamespace, + HelmReleaseNamespace: config.helmReleaseNamespace, + ModuleTargetNamespace: config.moduleTargetNamespace, + }, zap.New(), ) if err != nil { - panic(err) + log.Printf("Failed to create Kubernetes client: %v\n", err) + os.Exit(1) } templatesRepo := template.NewRepo( @@ -55,3 +71,31 @@ func main() { os.Exit(1) } } + +func loadConfig() *Config { + config := &Config{ + moduleNamespace: getEnvOrDefault("CYCLOPS_MODULE_NAMESPACE", "cyclops"), + helmReleaseNamespace: os.Getenv("CYCLOPS_HELM_RELEASE_NAMESPACE"), + moduleTargetNamespace: os.Getenv("CYCLOPS_MODULE_TARGET_NAMESPACE"), + kubeContext: os.Getenv("CYCLOPS_KUBE_CONTEXT"), + } + + config.kubeconfigPath = os.Getenv("KUBECONFIG") + if config.kubeconfigPath == "" { + if home, err := os.UserHomeDir(); err == nil { + defaultKubeconfig := filepath.Join(home, ".kube", "config") + if _, err := os.Stat(defaultKubeconfig); err == nil { + config.kubeconfigPath = defaultKubeconfig + } + } + } + + return config +} + +func getEnvOrDefault(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} diff --git a/go.mod b/go.mod index 446f1e6..96047a1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cyclops-ui/mcp-cyclops go 1.23.8 require ( - github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250422163445-4a15b13ad3a5 + github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250424103816-0aa958f49c5d github.com/mark3labs/mcp-go v0.22.0 k8s.io/apiextensions-apiserver v0.32.3 k8s.io/apimachinery v0.32.3 diff --git a/go.sum b/go.sum index 0b6a156..871dd01 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,13 @@ github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyclops-ui/cyclops v0.18.5/go.mod h1:6H1Dk8t18WQFYHUn1aGTTvwcrZGTdAnBh6qGcDRdtNk= github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250422163445-4a15b13ad3a5 h1:WD2f+0cfEC3QXKbUYUW8K8CH673Wezw6Ho+M5RQc5XY= github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250422163445-4a15b13ad3a5/go.mod h1:X9riUJ/32Bs2c3ZK2w1WXxHmZbpn/kh4YaLFICzbPuo= +github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250424075329-c9fd7a0fa219 h1:UrXhaTTIjM83uZJvPQ9ZjhbwI3385VoR66fZnjaQjKE= +github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250424075329-c9fd7a0fa219/go.mod h1:X9riUJ/32Bs2c3ZK2w1WXxHmZbpn/kh4YaLFICzbPuo= +github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250424103816-0aa958f49c5d h1:5P4qblnDB9W0n58v2zdpVJc7GvCQ7LO2X4yry4KX30c= +github.com/cyclops-ui/cyclops/cyclops-ctrl v0.0.0-20250424103816-0aa958f49c5d/go.mod h1:X9riUJ/32Bs2c3ZK2w1WXxHmZbpn/kh4YaLFICzbPuo= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=