mirror of
https://github.com/containers/kubernetes-mcp-server.git
synced 2025-10-23 01:22:57 +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>
121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
internalk8s "github.com/containers/kubernetes-mcp-server/pkg/kubernetes"
|
|
"github.com/containers/kubernetes-mcp-server/pkg/output"
|
|
"github.com/google/jsonschema-go/jsonschema"
|
|
)
|
|
|
|
type ServerTool struct {
|
|
Tool Tool
|
|
Handler ToolHandlerFunc
|
|
ClusterAware *bool
|
|
TargetListProvider *bool
|
|
}
|
|
|
|
// IsClusterAware indicates whether the tool can accept a "cluster" or "context" parameter
|
|
// to operate on a specific Kubernetes cluster context.
|
|
// Defaults to true if not explicitly set
|
|
func (s *ServerTool) IsClusterAware() bool {
|
|
if s.ClusterAware != nil {
|
|
return *s.ClusterAware
|
|
}
|
|
return true
|
|
}
|
|
|
|
// IsTargetListProvider indicates whether the tool is used to provide a list of targets (clusters/contexts)
|
|
// Defaults to false if not explicitly set
|
|
func (s *ServerTool) IsTargetListProvider() bool {
|
|
if s.TargetListProvider != nil {
|
|
return *s.TargetListProvider
|
|
}
|
|
return false
|
|
}
|
|
|
|
type Toolset interface {
|
|
// GetName returns the name of the toolset.
|
|
// Used to identify the toolset in configuration, logs, and command-line arguments.
|
|
// Examples: "core", "metrics", "helm"
|
|
GetName() string
|
|
GetDescription() string
|
|
GetTools(o internalk8s.Openshift) []ServerTool
|
|
}
|
|
|
|
type ToolCallRequest interface {
|
|
GetArguments() map[string]any
|
|
}
|
|
|
|
type ToolCallResult struct {
|
|
// Raw content returned by the tool.
|
|
Content string
|
|
// Error (non-protocol) to send back to the LLM.
|
|
Error error
|
|
}
|
|
|
|
func NewToolCallResult(content string, err error) *ToolCallResult {
|
|
return &ToolCallResult{
|
|
Content: content,
|
|
Error: err,
|
|
}
|
|
}
|
|
|
|
type ToolHandlerParams struct {
|
|
context.Context
|
|
*internalk8s.Kubernetes
|
|
ToolCallRequest
|
|
ListOutput output.Output
|
|
}
|
|
|
|
type ToolHandlerFunc func(params ToolHandlerParams) (*ToolCallResult, error)
|
|
|
|
type Tool struct {
|
|
// The name of the tool.
|
|
// Intended for programmatic or logical use, but used as a display name in past
|
|
// specs or fallback (if title isn't present).
|
|
Name string `json:"name"`
|
|
// A human-readable description of the tool.
|
|
//
|
|
// This can be used by clients to improve the LLM's understanding of available
|
|
// tools. It can be thought of like a "hint" to the model.
|
|
Description string `json:"description,omitempty"`
|
|
// Additional tool information.
|
|
Annotations ToolAnnotations `json:"annotations"`
|
|
// A JSON Schema object defining the expected parameters for the tool.
|
|
InputSchema *jsonschema.Schema
|
|
}
|
|
|
|
type ToolAnnotations struct {
|
|
// Human-readable title for the tool
|
|
Title string `json:"title,omitempty"`
|
|
// If true, the tool does not modify its environment.
|
|
ReadOnlyHint *bool `json:"readOnlyHint,omitempty"`
|
|
// If true, the tool may perform destructive updates to its environment. If
|
|
// false, the tool performs only additive updates.
|
|
//
|
|
// (This property is meaningful only when ReadOnlyHint == false.)
|
|
DestructiveHint *bool `json:"destructiveHint,omitempty"`
|
|
// If true, calling the tool repeatedly with the same arguments will have no
|
|
// additional effect on its environment.
|
|
//
|
|
// (This property is meaningful only when ReadOnlyHint == false.)
|
|
IdempotentHint *bool `json:"idempotentHint,omitempty"`
|
|
// If true, this tool may interact with an "open world" of external entities. If
|
|
// false, the tool's domain of interaction is closed. For example, the world of
|
|
// a web search tool is open, whereas that of a memory tool is not.
|
|
OpenWorldHint *bool `json:"openWorldHint,omitempty"`
|
|
}
|
|
|
|
func ToRawMessage(v any) json.RawMessage {
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return b
|
|
}
|