Skip to content

Commit a1e7c69

Browse files
authored
Tools chart & e2e with k8s (#12)
1 parent 4ab717c commit a1e7c69

39 files changed

+19092
-1280
lines changed

.github/workflows/ci.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ jobs:
6767
go-version: "1.24"
6868
cache: true
6969

70+
- name: Create k8s Kind Cluster
71+
uses: helm/kind-action@v1
72+
with:
73+
cluster_name: kagent
74+
config: scripts/kind/kind-config.yaml
75+
7076
- name: Run cmd/main.go tests
7177
working-directory: .
7278
run: |

.github/workflows/tag.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
5151
fi
5252
make docker-build
53+
make helm-publish
5354
release:
5455
# Only run release after images and helm chart are pushed
5556
# In the future we can take the chart from the helm action,

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ bin/
1111
/kagent-tools
1212
/*.out
1313
*.html
14+
/helm/kagent-tools/Chart.yaml
15+
/reports/tools-cve.csv

Makefile

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
DOCKER_REGISTRY ?= ghcr.io
22
BASE_IMAGE_REGISTRY ?= cgr.dev
3+
34
DOCKER_REPO ?= kagent-dev/kagent
5+
6+
HELM_REPO ?= oci://ghcr.io/kagent-dev
7+
HELM_ACTION=upgrade --install
8+
49
KIND_CLUSTER_NAME ?= kagent
10+
KIND_IMAGE_VERSION ?= 1.33.1
11+
KIND_CREATE_CMD ?= "kind create cluster --name $(KIND_CLUSTER_NAME) --image kindest/node:v$(KIND_IMAGE_VERSION) --config ./scripts/kind/kind-config.yaml"
512

613
BUILD_DATE := $(shell date -u '+%Y-%m-%d')
714
GIT_COMMIT := $(shell git rev-parse --short HEAD || echo "unknown")
@@ -12,6 +19,7 @@ LDFLAGS := -X github.com/kagent-dev/tools/internal/version.Version=$(VERSION) -X
1219

1320
## Location to install dependencies to
1421
LOCALBIN ?= $(shell pwd)/bin
22+
HELM_DIST_FOLDER ?= $(shell pwd)/dist
1523

1624
.PHONY: clean
1725
clean:
@@ -55,8 +63,8 @@ test-only: ## Run tests only (without build/lint for faster iteration)
5563
go test -tags=test -v -cover ./pkg/... ./internal/...
5664

5765
.PHONY: e2e
58-
e2e: test docker-build
59-
go test -tags=test -v -cover ./e2e/...
66+
e2e: test retag
67+
go test -v -tags=test -cover ./test/e2e/ -timeout 5m
6068

6169
bin/kagent-tools-linux-amd64:
6270
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o bin/kagent-tools-linux-amd64 ./cmd
@@ -89,7 +97,7 @@ bin/kagent-tools-windows-amd64.exe.sha256: bin/kagent-tools-windows-amd64.exe
8997
sha256sum bin/kagent-tools-windows-amd64.exe > bin/kagent-tools-windows-amd64.exe.sha256
9098

9199
.PHONY: build
92-
build: $(LOCALBIN) bin/kagent-tools-linux-amd64.sha256 bin/kagent-tools-linux-arm64.sha256 bin/kagent-tools-darwin-amd64.sha256 bin/kagent-tools-darwin-arm64.sha256 bin/kagent-tools-windows-amd64.exe.sha256
100+
build: $(LOCALBIN) clean bin/kagent-tools-linux-amd64.sha256 bin/kagent-tools-linux-arm64.sha256 bin/kagent-tools-darwin-amd64.sha256 bin/kagent-tools-darwin-arm64.sha256 bin/kagent-tools-windows-amd64.exe.sha256
93101
build:
94102
@echo "Build complete. Binaries are available in the bin/ directory."
95103
ls -lt bin/kagent-tools-*
@@ -100,8 +108,10 @@ run: docker-build
100108
@echo "Use: npx @modelcontextprotocol/inspector to connect to the tool server"
101109
@docker run --rm --net=host -p 8084:8084 -e OPENAI_API_KEY=$(OPENAI_API_KEY) -v $(HOME)/.kube:/home/nonroot/.kube -e KAGENT_TOOLS_PORT=8084 $(TOOLS_IMG) -- --kubeconfig /root/.kube/config
102110

103-
PHONY: retag
104-
retag: docker-build
111+
.PHONY: retag
112+
retag: docker-build helm-version
113+
@echo "Check Kind cluster $(KIND_CLUSTER_NAME) exists"
114+
kind get clusters | grep -q $(KIND_CLUSTER_NAME) || bash -c $(KIND_CREATE_CMD)
105115
@echo "Retagging tools image to $(RETAGGED_TOOLS_IMG)"
106116
docker tag $(TOOLS_IMG) $(RETAGGED_TOOLS_IMG)
107117
kind load docker-image --name $(KIND_CLUSTER_NAME) $(RETAGGED_TOOLS_IMG)
@@ -127,7 +137,7 @@ DOCKER_BUILD_ARGS ?= --pull --load --platform linux/$(LOCALARCH) --builder $(BUI
127137
TOOLS_ISTIO_VERSION ?= 1.26.2
128138
TOOLS_ARGO_ROLLOUTS_VERSION ?= 1.8.3
129139
TOOLS_KUBECTL_VERSION ?= 1.33.2
130-
TOOLS_HELM_VERSION ?= 3.18.3
140+
TOOLS_HELM_VERSION ?= 3.18.4
131141
TOOLS_CILIUM_VERSION ?= 0.18.5
132142

133143
# build args
@@ -155,11 +165,55 @@ docker-build-all: DOCKER_BUILD_ARGS = --progress=plain --builder $(BUILDX_BUILDE
155165
docker-build-all:
156166
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) $(TOOLS_IMAGE_BUILD_ARGS) -f Dockerfile ./
157167

168+
.PHONY: helm-version
169+
helm-version:
170+
VERSION=$(VERSION) envsubst < helm/kagent-tools/Chart-template.yaml > helm/kagent-tools/Chart.yaml
171+
mkdir -p $(HELM_DIST_FOLDER)
172+
helm package -d $(HELM_DIST_FOLDER) helm/kagent-tools
173+
174+
.PHONY: helm-uninstall
175+
helm-uninstall:
176+
helm uninstall kagent --namespace kagent --kube-context kind-$(KIND_CLUSTER_NAME) --wait
177+
178+
.PHONY: helm-install
179+
helm-install: helm-version
180+
helm $(HELM_ACTION) kagent-tools ./helm/kagent-tools \
181+
--kube-context kind-$(KIND_CLUSTER_NAME) \
182+
--namespace kagent \
183+
--create-namespace \
184+
--history-max 2 \
185+
--timeout 5m \
186+
-f ./scripts/kind/test-values.yaml \
187+
--set tools.image.registry=$(RETAGGED_DOCKER_REGISTRY) \
188+
--wait
189+
190+
.PHONY: helm-publish
191+
helm-publish: helm-version
192+
helm push ./$(HELM_DIST_FOLDER)/kagent-tools-$(VERSION).tgz $(HELM_REPO)/tools/helm
193+
194+
.PHONY: create-kind-cluster
195+
create-kind-cluster:
196+
docker pull kindest/node:v$(KIND_IMAGE_VERSION) || true
197+
bash -c $(KIND_CREATE_CMD)
198+
199+
.PHONY: delete-kind-cluster
200+
delete-kind-cluster:
201+
kind delete cluster --name $(KIND_CLUSTER_NAME)
202+
158203
.PHONY: kind-update-kagent
159-
kind-update-kagent: docker-build
160-
kind get clusters | grep -q $(KIND_CLUSTER_NAME) || kind create cluster --name $(KIND_CLUSTER_NAME)
161-
kind load docker-image --name $(KIND_CLUSTER_NAME) $(TOOLS_IMG)
162-
kubectl patch --namespace kagent deployment/kagent --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/3/image", "value": "$(TOOLS_IMG)"}]'
204+
kind-update-kagent: retag
205+
kubectl patch --namespace kagent deployment/kagent --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/3/image", "value": "$(RETAGGED_TOOLS_IMG)"}]'
206+
207+
.PHONY: otel-local
208+
otel-local:
209+
docker rm -f jaeger-desktop || true
210+
docker run -d --name jaeger-desktop --restart=always -p 16686:16686 -p 4317:4317 -p 4318:4318 jaegertracing/jaeger:2.7.0
211+
open http://localhost:16686/
212+
213+
.PHONY: report/image-cve
214+
report/image-cve: docker-build govulncheck
215+
echo "Running CVE scan :: CVE -> CSV ... reports/$(SEMVER)/"
216+
grype docker:$(TOOLS_IMG) -o template -t reports/cve-report.tmpl --file reports/$(SEMVER)/tools-cve.csv
163217

164218
## Tool Binaries
165219
## Location to install dependencies t

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@
2424

2525
This directory contains the Go implementation of all KAgent tools, migrated from the original Python implementation. The tools are designed to work with the Model Context Protocol (MCP) server and provide comprehensive Kubernetes, cloud-native, and observability functionality.
2626

27+
## Installation
28+
29+
- **Bash:**
30+
31+
`curl -sL https://github.com/kagent-dev/tools/blob/main/scripts/install.sh | bash`
32+
33+
- **Docker:**
34+
35+
`docker run -it --rm ghcr.io/kagent-dev/kagent/tools:<version>`
36+
37+
- **Kubernetes**
38+
39+
`helm upgrade -i kagent-tools --version <version> oci://ghcr.io/kagent-dev/tools/helm/`
40+
41+
2742
## Architecture
2843

2944
The Go tools are implemented as a single MCP server that exposes all available tools through the MCP protocol.

cmd/main.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ import (
3333
)
3434

3535
var (
36-
port int
37-
stdio bool
38-
tools []string
39-
kubeconfig *string
36+
port int
37+
stdio bool
38+
tools []string
39+
kubeconfig *string
40+
showVersion bool
4041

4142
// These variables should be set during build time using -ldflags
4243
Name = "kagent-tools-server"
@@ -55,6 +56,7 @@ func init() {
5556
rootCmd.Flags().IntVarP(&port, "port", "p", 8084, "Port to run the server on")
5657
rootCmd.Flags().BoolVar(&stdio, "stdio", false, "Use stdio for communication instead of HTTP")
5758
rootCmd.Flags().StringSliceVar(&tools, "tools", []string{}, "List of tools to register. If empty, all tools are registered.")
59+
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "Show version information and exit")
5860
kubeconfig = rootCmd.Flags().String("kubeconfig", "", "kubeconfig file path (optional, defaults to in-cluster config)")
5961

6062
// if found .env file, load it
@@ -70,7 +72,23 @@ func main() {
7072
}
7173
}
7274

75+
// printVersion displays version information in a formatted way
76+
func printVersion() {
77+
fmt.Printf("%s\n", Name)
78+
fmt.Printf("Version: %s\n", Version)
79+
fmt.Printf("Git Commit: %s\n", GitCommit)
80+
fmt.Printf("Build Date: %s\n", BuildDate)
81+
fmt.Printf("Go Version: %s\n", runtime.Version())
82+
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
83+
}
84+
7385
func run(cmd *cobra.Command, args []string) {
86+
// Handle version flag early, before any initialization
87+
if showVersion {
88+
printVersion()
89+
return
90+
}
91+
7492
logger.Init()
7593
defer logger.Sync()
7694

@@ -130,7 +148,9 @@ func run(cmd *cobra.Command, args []string) {
130148
runStdioServer(ctx, mcp)
131149
}()
132150
} else {
133-
sseServer := server.NewStreamableHTTPServer(mcp)
151+
sseServer := server.NewStreamableHTTPServer(mcp,
152+
server.WithHeartbeatInterval(30*time.Second),
153+
)
134154

135155
// Create a mux to handle different routes
136156
mux := http.NewServeMux()

0 commit comments

Comments
 (0)