Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
tools []string
kubeconfig *string
showVersion bool
readOnly bool

// These variables should be set during build time using -ldflags
Name = "kagent-tools-server"
Expand All @@ -58,6 +59,7 @@ func init() {
rootCmd.Flags().BoolVar(&stdio, "stdio", false, "Use stdio for communication instead of HTTP")
rootCmd.Flags().StringSliceVar(&tools, "tools", []string{}, "List of tools to register. If empty, all tools are registered.")
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "Show version information and exit")
rootCmd.Flags().BoolVar(&readOnly, "read-only", false, "Run in read-only mode (disable tools that perform write operations)")
kubeconfig = rootCmd.Flags().String("kubeconfig", "", "kubeconfig file path (optional, defaults to in-cluster config)")

// if found .env file, load it
Expand Down Expand Up @@ -119,17 +121,21 @@ func run(cmd *cobra.Command, args []string) {
attribute.Bool("server.stdio_mode", stdio),
attribute.Int("server.port", port),
attribute.StringSlice("server.tools", tools),
attribute.Bool("server.read_only", readOnly),
)

logger.Get().Info("Starting "+Name, "version", Version, "git_commit", GitCommit, "build_date", BuildDate)
if readOnly {
logger.Get().Info("Running in read-only mode - write operations are disabled")
}

mcp := server.NewMCPServer(
Name,
Version,
)

// Register tools
registerMCP(mcp, tools, *kubeconfig)
registerMCP(mcp, tools, *kubeconfig, readOnly)

// Create wait group for server goroutines
var wg sync.WaitGroup
Expand Down Expand Up @@ -285,14 +291,14 @@ func runStdioServer(ctx context.Context, mcp *server.MCPServer) {
}
}

func registerMCP(mcp *server.MCPServer, enabledToolProviders []string, kubeconfig string) {
func registerMCP(mcp *server.MCPServer, enabledToolProviders []string, kubeconfig string, readOnly bool) {
// A map to hold tool providers and their registration functions
toolProviderMap := map[string]func(*server.MCPServer){
"argo": argo.RegisterTools,
"cilium": cilium.RegisterTools,
"helm": helm.RegisterTools,
"istio": istio.RegisterTools,
"k8s": func(s *server.MCPServer) { k8s.RegisterTools(s, nil, kubeconfig) },
"argo": func(s *server.MCPServer) { argo.RegisterTools(s, readOnly) },
"cilium": func(s *server.MCPServer) { cilium.RegisterTools(s, readOnly) },
"helm": func(s *server.MCPServer) { helm.RegisterTools(s, readOnly) },
"istio": func(s *server.MCPServer) { istio.RegisterTools(s, readOnly) },
"k8s": func(s *server.MCPServer) { k8s.RegisterTools(s, nil, kubeconfig, readOnly) },
"kubescape": func(s *server.MCPServer) { kubescape.RegisterTools(s, kubeconfig) },
"prometheus": prometheus.RegisterTools,
"utils": utils.RegisterTools,
Expand Down
60 changes: 32 additions & 28 deletions pkg/argo/argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ func handleListRollouts(ctx context.Context, request mcp.CallToolRequest) (*mcp.
return mcp.NewToolResultText(output), nil
}

func RegisterTools(s *server.MCPServer) {
func RegisterTools(s *server.MCPServer, readOnly bool) {
// Read-only tools - always registered
s.AddTool(mcp.NewTool("argo_verify_argo_rollouts_controller_install",
mcp.WithDescription("Verify that the Argo Rollouts controller is installed and running"),
mcp.WithString("namespace", mcp.Description("The namespace where Argo Rollouts is installed")),
Expand All @@ -392,36 +393,39 @@ func RegisterTools(s *server.MCPServer) {
mcp.WithString("type", mcp.Description("What to list: rollouts or experiments"), mcp.DefaultString("rollouts")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_rollouts_list", handleListRollouts)))

s.AddTool(mcp.NewTool("argo_promote_rollout",
mcp.WithDescription("Promote a paused rollout to the next step"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to promote"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
mcp.WithString("full", mcp.Description("Promote the rollout to the final step")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_promote_rollout", handlePromoteRollout)))

s.AddTool(mcp.NewTool("argo_pause_rollout",
mcp.WithDescription("Pause a rollout"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to pause"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_pause_rollout", handlePauseRollout)))

s.AddTool(mcp.NewTool("argo_set_rollout_image",
mcp.WithDescription("Set the image of a rollout"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to set the image for"), mcp.Required()),
mcp.WithString("container_image", mcp.Description("The container image to set for the rollout"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_set_rollout_image", handleSetRolloutImage)))

s.AddTool(mcp.NewTool("argo_verify_gateway_plugin",
mcp.WithDescription("Verify the installation status of the Argo Rollouts Gateway API plugin"),
mcp.WithString("version", mcp.Description("The version of the plugin to check")),
mcp.WithString("namespace", mcp.Description("The namespace for the plugin resources")),
mcp.WithString("should_install", mcp.Description("Whether to install the plugin if not found")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_verify_gateway_plugin", handleVerifyGatewayPlugin)))

s.AddTool(mcp.NewTool("argo_check_plugin_logs",
mcp.WithDescription("Check the logs of the Argo Rollouts Gateway API plugin"),
mcp.WithString("namespace", mcp.Description("The namespace of the plugin resources")),
mcp.WithString("timeout", mcp.Description("Timeout for log collection in seconds")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_check_plugin_logs", handleCheckPluginLogs)))

// Write tools - only registered when not in read-only mode
if !readOnly {
s.AddTool(mcp.NewTool("argo_promote_rollout",
mcp.WithDescription("Promote a paused rollout to the next step"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to promote"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
mcp.WithString("full", mcp.Description("Promote the rollout to the final step")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_promote_rollout", handlePromoteRollout)))

s.AddTool(mcp.NewTool("argo_pause_rollout",
mcp.WithDescription("Pause a rollout"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to pause"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_pause_rollout", handlePauseRollout)))

s.AddTool(mcp.NewTool("argo_set_rollout_image",
mcp.WithDescription("Set the image of a rollout"),
mcp.WithString("rollout_name", mcp.Description("The name of the rollout to set the image for"), mcp.Required()),
mcp.WithString("container_image", mcp.Description("The container image to set for the rollout"), mcp.Required()),
mcp.WithString("namespace", mcp.Description("The namespace of the rollout")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_set_rollout_image", handleSetRolloutImage)))

s.AddTool(mcp.NewTool("argo_verify_gateway_plugin",
mcp.WithDescription("Verify the installation status of the Argo Rollouts Gateway API plugin"),
mcp.WithString("version", mcp.Description("The version of the plugin to check")),
mcp.WithString("namespace", mcp.Description("The namespace for the plugin resources")),
mcp.WithString("should_install", mcp.Description("Whether to install the plugin if not found")),
), telemetry.AdaptToolHandler(telemetry.WithTracing("argo_verify_gateway_plugin", handleVerifyGatewayPlugin)))
}
}
Loading