mirror of
https://github.com/openshift/openshift-mcp-server.git
synced 2025-10-17 14:27:48 +03:00
* 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>
70 lines
2.3 KiB
Go
70 lines
2.3 KiB
Go
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
"github.com/mark3labs/mcp-go/server"
|
|
|
|
"github.com/containers/kubernetes-mcp-server/pkg/api"
|
|
)
|
|
|
|
func ServerToolToM3LabsServerTool(s *Server, tools []api.ServerTool) ([]server.ServerTool, error) {
|
|
m3labTools := make([]server.ServerTool, 0)
|
|
for _, tool := range tools {
|
|
m3labTool := mcp.Tool{
|
|
Name: tool.Tool.Name,
|
|
Description: tool.Tool.Description,
|
|
Annotations: mcp.ToolAnnotation{
|
|
Title: tool.Tool.Annotations.Title,
|
|
ReadOnlyHint: tool.Tool.Annotations.ReadOnlyHint,
|
|
DestructiveHint: tool.Tool.Annotations.DestructiveHint,
|
|
IdempotentHint: tool.Tool.Annotations.IdempotentHint,
|
|
OpenWorldHint: tool.Tool.Annotations.OpenWorldHint,
|
|
},
|
|
}
|
|
if tool.Tool.InputSchema != nil {
|
|
schema, err := json.Marshal(tool.Tool.InputSchema)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal tool input schema for tool %s: %v", tool.Tool.Name, err)
|
|
}
|
|
// TODO: temporary fix to append an empty properties object (some client have trouble parsing a schema without properties)
|
|
// As opposed, Gemini had trouble for a while when properties was present but empty.
|
|
// https://github.com/containers/kubernetes-mcp-server/issues/340
|
|
if string(schema) == `{"type":"object"}` {
|
|
schema = []byte(`{"type":"object","properties":{}}`)
|
|
}
|
|
m3labTool.RawInputSchema = schema
|
|
}
|
|
m3labHandler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
// get the correct internalk8s.Manager for the target specified in the request
|
|
cluster := request.GetString(s.p.GetTargetParameterName(), s.p.GetDefaultTarget())
|
|
m, err := s.p.GetManagerFor(ctx, cluster)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// derive the manager based on auth on top of the settings for the cluster
|
|
k, err := m.Derived(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := tool.Handler(api.ToolHandlerParams{
|
|
Context: ctx,
|
|
Kubernetes: k,
|
|
ToolCallRequest: request,
|
|
ListOutput: s.configuration.ListOutput(),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewTextResult(result.Content, result.Error), nil
|
|
}
|
|
m3labTools = append(m3labTools, server.ServerTool{Tool: m3labTool, Handler: m3labHandler})
|
|
}
|
|
return m3labTools, nil
|
|
}
|