Skip to main content
Glama
tools.go5.53 kB
// Copyright 2025 The Inspektor Gadget authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tools import ( "context" "fmt" "log/slog" "sync" "github.com/mark3labs/mcp-go/server" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/inspektor-gadget/ig-mcp-server/pkg/discoverer" "github.com/inspektor-gadget/ig-mcp-server/pkg/gadgetmanager" gadgetsdefault "github.com/inspektor-gadget/ig-mcp-server/pkg/tools/gadgets/default" gadgetsephemeral "github.com/inspektor-gadget/ig-mcp-server/pkg/tools/gadgets/ephemeral" lifecycledeploy "github.com/inspektor-gadget/ig-mcp-server/pkg/tools/lifecycle/deploy" lifecyclegadgets "github.com/inspektor-gadget/ig-mcp-server/pkg/tools/lifecycle/gadgets" ) var log = slog.Default().With("component", "tools") type ToolRegistryCallback func(tool ...server.ServerTool) // GadgetToolRegistry is a simple registry for server tools based on gadgets. type GadgetToolRegistry struct { tools map[string]server.ServerTool mu sync.Mutex callbacks []ToolRegistryCallback readonly bool gadgetMgr gadgetmanager.GadgetManager k8sConfig *genericclioptions.ConfigFlags discoverer discoverer.Discoverer env string } // NewToolRegistry creates a new GadgetToolRegistry instance. func NewToolRegistry(manager gadgetmanager.GadgetManager, env string, k8sConfig *genericclioptions.ConfigFlags, discoverer discoverer.Discoverer, readonly bool) *GadgetToolRegistry { return &GadgetToolRegistry{ tools: make(map[string]server.ServerTool), gadgetMgr: manager, env: env, k8sConfig: k8sConfig, discoverer: discoverer, readonly: readonly, } } func (r *GadgetToolRegistry) all() []server.ServerTool { tools := make([]server.ServerTool, 0, len(r.tools)) for _, tool := range r.tools { if r.readonly && tool.Tool.Annotations.ReadOnlyHint != nil && !*tool.Tool.Annotations.ReadOnlyHint { // If the registry is in read-only mode, skip tools that do not have the read-only hint annotation continue } tools = append(tools, tool) } return tools } func (r *GadgetToolRegistry) RegisterTools(tools ...server.ServerTool) { for _, tool := range tools { log.Debug("Registering tool", "name", tool.Tool.Name) r.tools[tool.Tool.Name] = tool } for _, callback := range r.callbacks { log.Debug("Invoking tool registry callback", "tools_count", len(r.tools)) callback(r.all()...) } } func (r *GadgetToolRegistry) RegisterCallback(callback ToolRegistryCallback) { r.callbacks = append(r.callbacks, callback) } func (r *GadgetToolRegistry) Prepare(ctx context.Context, images []string) error { r.mu.Lock() defer r.mu.Unlock() gadgets := discoverer.FromImages(images) var err error if len(gadgets) == 0 && r.discoverer != nil { gadgets, err = r.discoverer.ListGadgets() if err != nil { log.Warn("listing gadgets from discoverer", "error", err) } } // if still no gadgets, fall back to builtin discoverer if len(gadgets) == 0 { dis := discoverer.NewBuiltinDiscoverer() gadgets, err = dis.ListGadgets() if err != nil { return fmt.Errorf("listing gadgets from builtin discoverer: %w", err) } } var tools []server.ServerTool // Register gadgets lifecycle tools and environment-specific tools if r.env == "kubernetes" { tools = append(tools, r.getK8sTools(ctx, gadgets)...) } if r.env == "linux" { tools = append(tools, r.getLinuxTools(gadgets)...) } // Register all tools in the registry r.RegisterTools(tools...) return nil } func (r *GadgetToolRegistry) getK8sTools(ctx context.Context, gadgets []discoverer.Gadget) []server.ServerTool { var tools []server.ServerTool // Register Gadget lifecycle tool tools = append(tools, lifecyclegadgets.GetTool(r.gadgetMgr)) // Register Inspektor Gadget lifecycle tool since we are in Kubernetes toolRefresher := func() { go func() { tools = r.getK8sTools(ctx, gadgets) r.RegisterTools(tools...) }() } tools = append(tools, lifecycledeploy.GetTool(toolRefresher)) deployed, _, err := lifecycledeploy.IsInspektorGadgetDeployed(ctx) if err != nil { log.Warn("Failed to check if Inspektor Gadget is deployed, skipping Inspektor Gadget lifecycle tool", "error", err) } // Register tools based on gadgets only if Inspektor Gadget is deployed if deployed { tools = append(tools, gadgetsdefault.GetTools(ctx, r.gadgetMgr, r.env, gadgets)...) } else { tools = append(tools, gadgetsephemeral.GetTools(gadgets)...) } return tools } func (r *GadgetToolRegistry) getLinuxTools(gadgets []discoverer.Gadget) []server.ServerTool { var tools []server.ServerTool // Register Gadget lifecycle tool tools = append(tools, lifecyclegadgets.GetTool(r.gadgetMgr)) // Check if the ig daemon is running by getting its version _, err := r.gadgetMgr.GetVersion() if err != nil { log.Warn("Failed to get ig daemon version, skipping gadget lifecycle tools", "error", err) return tools } tools = append(tools, gadgetsdefault.GetTools(context.Background(), r.gadgetMgr, r.env, gadgets)...) return tools }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/inspektor-gadget/ig-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server