feat: Multi Cluster Support (#348)

* feat: add cluster provider for kubeconfig

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: move server to use ClusterProvider interface

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: authentication middleware works with cluster provider

Signed-off-by: Calum Murray <cmurray@redhat.com>

* fix: unit tests work after cluster provider changes

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: add tool mutator to add cluster parameter

Signed-off-by: Calum Murray <cmurray@redhat.com>

* test: handle cluster parameter

Signed-off-by: Calum Murray <cmurray@redhat.com>

* fix: handle lazy init correctly

Signed-off-by: Calum Murray <cmurray@redhat.com>

* refactor: move to using multi-strategy ManagerProvider

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: add contexts_list tool

Signed-off-by: Calum Murray <cmurray@redhat.com>

* refactor: make tool mutator generic between cluster/context naming

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: introduce tool filter

Signed-off-by: Calum Murray <cmurray@redhat.com>

* refactor: use new ManagerProvider/mutator/filter within mcp server

Signed-off-by: Calum Murray <cmurray@redhat.com>

* fix(test): tests expect context parameter in tool defs

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: auth handles multi-cluster case correctly

Signed-off-by: Calum Murray <cmurray@redhat.com>

* fix: small changes from local testing

Signed-off-by: Calum Murray <cmurray@redhat.com>

* chore: fix enum test

Signed-off-by: Calum Murray <cmurray@redhat.com>

* review: Multi Cluster support (#1)

* nit: rename contexts_list to configuration_contexts_list

Besides the conventional naming, it helps LLMs understand the context of the tool by providing a certain level of hierarchy.

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* fix(mcp): ToolMutator doesn't rely on magic strings

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* refactor(api): don't expose ManagerProvider to toolsets

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* test(mcp): configuration_contexts_list basic tests

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* test(toolsets): revert edge-case test

This test should not be touched.

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* test(toolsets): add specific metadata tests for multi-cluster

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* fix(mcp): ToolFilter doesn't rely on magic strings (partially)

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* test(api): IsClusterAware and IsTargetListProvider default values

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* test(mcp): revert unneeded changes in mcp_tools_test.go

Signed-off-by: Marc Nuri <marc@marcnuri.com>

---------

Signed-off-by: Marc Nuri <marc@marcnuri.com>

* fix: always include configuration_contexts_list if contexts > 1

Signed-off-by: Calum Murray <cmurray@redhat.com>

* feat: include server urls in configuration_contexts_list

Signed-off-by: Calum Murray <cmurray@redhat.com>

---------

Signed-off-by: Calum Murray <cmurray@redhat.com>
Signed-off-by: Marc Nuri <marc@marcnuri.com>
Co-authored-by: Marc Nuri <marc@marcnuri.com>
This commit is contained in:
Calum Murray
2025-10-06 06:01:16 -04:00
committed by GitHub
parent c447bf819f
commit a2d16e9f41
21 changed files with 2529 additions and 95 deletions

View File

@@ -8,15 +8,10 @@ func KubeConfigFake() *clientcmdapi.Config {
fakeConfig := clientcmdapi.NewConfig()
fakeConfig.Clusters["fake"] = clientcmdapi.NewCluster()
fakeConfig.Clusters["fake"].Server = "https://127.0.0.1:6443"
fakeConfig.Clusters["additional-cluster"] = clientcmdapi.NewCluster()
fakeConfig.AuthInfos["fake"] = clientcmdapi.NewAuthInfo()
fakeConfig.AuthInfos["additional-auth"] = clientcmdapi.NewAuthInfo()
fakeConfig.Contexts["fake-context"] = clientcmdapi.NewContext()
fakeConfig.Contexts["fake-context"].Cluster = "fake"
fakeConfig.Contexts["fake-context"].AuthInfo = "fake"
fakeConfig.Contexts["additional-context"] = clientcmdapi.NewContext()
fakeConfig.Contexts["additional-context"].Cluster = "additional-cluster"
fakeConfig.Contexts["additional-context"].AuthInfo = "additional-auth"
fakeConfig.CurrentContext = "fake-context"
return fakeConfig
}

View File

@@ -73,10 +73,14 @@ func (m *MockServer) Kubeconfig() *api.Config {
}
func (m *MockServer) KubeconfigFile(t *testing.T) string {
kubeconfig := filepath.Join(t.TempDir(), "config")
err := clientcmd.WriteToFile(*m.Kubeconfig(), kubeconfig)
return KubeconfigFile(t, m.Kubeconfig())
}
func KubeconfigFile(t *testing.T, kubeconfig *api.Config) string {
kubeconfigFile := filepath.Join(t.TempDir(), "config")
err := clientcmd.WriteToFile(*kubeconfig, kubeconfigFile)
require.NoError(t, err, "Expected no error writing kubeconfig file")
return kubeconfig
return kubeconfigFile
}
func WriteObject(w http.ResponseWriter, obj runtime.Object) {