Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ name: Lint

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
lint:
Expand Down
112 changes: 112 additions & 0 deletions .github/workflows/tag.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Tag and Push

on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
version:
description: 'Version number'

# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#release
# GITHUB_SHA = Last commit in the tagged release
# GITHUB_REF = Tag ref of release refs/tags/<tag_name>
jobs:
push-images:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: 'Checkout GitHub Action'
uses: actions/checkout@main

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
name: kmcp-builder-v0.23.0
platforms: linux/amd64,linux/arm64
version: v0.23.0
use: 'true'
- name: 'Build Images'
env:
DOCKER_BUILDER: "docker buildx"
DOCKER_BUILD_ARGS: "--push --platform linux/amd64,linux/arm64"
run: |
# if workflow_dispatch is used, use the version input
if [ -n "${{ github.event.inputs.version }}" ]; then
export VERSION=${{ github.event.inputs.version }}
else
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
fi
echo "Building Docker image with version: ${VERSION}"
make docker-build VERSION=${VERSION}
push-helm-chart:
needs:
- push-images
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: 'Checkout GitHub Action'
uses: actions/checkout@main

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: 'Build and Publish Helm Chart'
run: |
# if workflow_dispatch is used, use the version input
if [ -n "${{ github.event.inputs.version }}" ]; then
export VERSION=${{ github.event.inputs.version }}
else
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
fi
echo "Publishing Helm chart with version: ${VERSION}"
make helm-publish VERSION=${VERSION}
release:
# Only run release after images and helm chart are pushed
# In the future we can take the chart from the helm action,
# and build the CLI beforehand.
needs:
- push-helm-chart
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: |
# if workflow_dispatch is used, use the version input
if [ -n "${{ github.event.inputs.version }}" ]; then
export VERSION=${{ github.event.inputs.version }}
else
export VERSION=$(echo "$GITHUB_REF" | cut -c12-)
fi
echo "Building release artifacts with version: ${VERSION}"
make build VERSION=${VERSION}
make helm-package VERSION=${VERSION}
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
# TODO: Add kmcp binary to the release
with:
files: |
dist/kmcp-*.tgz

17 changes: 5 additions & 12 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ name: E2E Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test-e2e:
Expand All @@ -17,19 +19,10 @@ jobs:
with:
go-version-file: go.mod

- name: Install the latest version of kind
run: |
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

- name: Verify kind installation
run: kind version

- name: Create kind cluster
run: kind create cluster

- name: Create k8s Kind Cluster
uses: helm/kind-action@v1
- name: Running Test e2e
run: |
kind create cluster
go mod tidy
make test-e2e
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ go.work
*.swp
*.swo
*~
# helm
dist/
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM docker.io/golang:1.24 AS builder
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.24 AS builder
ARG TARGETOS
ARG TARGETARCH

Expand Down Expand Up @@ -31,4 +31,9 @@ WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532


LABEL org.opencontainers.image.source=https://github.com/kagent-dev/kmcp
LABEL org.opencontainers.image.description="KMCP is the Kubernetes MCP Server Controller."
LABEL org.opencontainers.image.authors="KAgent Creators 🤖"

ENTRYPOINT ["/manager"]
139 changes: 80 additions & 59 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Image URL to use all building/pushing image targets
IMG ?= controller:latest

# Image configuration
DOCKER_REGISTRY ?= ghcr.io
BASE_IMAGE_REGISTRY ?= cgr.dev
DOCKER_REPO ?= kagent-dev/kmcp
HELM_REPO ?= oci://ghcr.io/kagent-dev
HELM_DIST_FOLDER ?= dist

BUILD_DATE := $(shell date -u '+%Y-%m-%d')
GIT_COMMIT := $(shell git rev-parse --short HEAD || echo "unknown")
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null | sed 's/-dirty//' | grep v || echo "v0.0.1+$(GIT_COMMIT)")

# Local architecture detection to build for the current platform
LOCALARCH ?= $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')

# Docker buildx configuration
BUILDKIT_VERSION = v0.23.0
BUILDX_NO_DEFAULT_ATTESTATIONS=1
BUILDX_BUILDER_NAME ?= kmcp-builder-$(BUILDKIT_VERSION)
DOCKER_BUILDER ?= docker buildx
DOCKER_BUILD_ARGS ?= --builder $(BUILDX_BUILDER_NAME) --pull --load --platform linux/$(LOCALARCH)

# Image configuration
CONTROLLER_IMAGE_NAME ?= controller
CONTROLLER_IMAGE_TAG ?= $(VERSION)
CONTROLLER_IMG ?= $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(CONTROLLER_IMAGE_NAME):$(CONTROLLER_IMAGE_TAG)

# Image URL to use all building/pushing image targets (backward compatibility)
IMG ?= $(CONTROLLER_IMG)
DIST_FOLDER ?= dist

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand All @@ -8,12 +36,6 @@ else
GOBIN=$(shell go env GOBIN)
endif

# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker

# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
Expand Down Expand Up @@ -45,6 +67,51 @@ help: ## Display this help.
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: helm-lint
helm-lint:
helm lint helm/kmcp

.PHONY: helm-package
helm-package:
mkdir -p $(DIST_FOLDER)
@echo "Packaging Helm chart with version $(VERSION)..."
@cp helm/kmcp/Chart.yaml helm/kmcp/Chart.yaml.bak
@sed "s/^version: .*/version: $(VERSION)/" helm/kmcp/Chart.yaml.bak > helm/kmcp/Chart.yaml
@helm package helm/kmcp --version $(VERSION) -d $(DIST_FOLDER)
@mv helm/kmcp/Chart.yaml.bak helm/kmcp/Chart.yaml

.PHONY: helm-cleanup
helm-cleanup: ## Clean up Helm chart packages
rm -f $(DIST_FOLDER)/*.tgz

.PHONY: helm-build
helm-build: helm-lint helm-package ## Build and package the Helm chart
@echo "Helm chart built successfully"

.PHONY: helm-publish
helm-publish: helm-package ## Publish Helm chart to OCI registry
@echo "Publishing Helm chart to $(HELM_REPO)/kmcp/helm..."
@helm push $(HELM_DIST_FOLDER)/kmcp-$(VERSION).tgz $(HELM_REPO)/kmcp/helm
@echo "Helm chart published successfully"

.PHONY: helm-test
helm-test:
@echo "Running Helm chart unit tests..."
@command -v helm >/dev/null 2>&1 || { \
echo "Helm is not installed. Please install Helm manually."; \
exit 1; \
}
@helm plugin list | grep -q 'unittest' || { \
echo "Installing helm-unittest plugin..."; \
helm plugin install https://github.com/quintush/helm-unittest; \
}
@helm unittest helm/kmcp
@echo "Helm chart unit tests completed successfully"

.PHONY: manifests-all
manifests-all: manifests ## Generate Kustomize from source definitions.
@echo "All manifests (Kustomize and Helm) updated successfully"

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
Expand Down Expand Up @@ -105,57 +172,15 @@ run: manifests generate fmt vet ## Run a controller from your host.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .
- $(DOCKER_BUILDER) create --name $(BUILDX_BUILDER_NAME)
$(DOCKER_BUILDER) use $(BUILDX_BUILDER_NAME)
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -t ${CONTROLLER_IMG} .
- $(DOCKER_BUILDER) rm $(BUILDX_BUILDER_NAME)

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
$(CONTAINER_TOOL) push ${IMG}

# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name kmcp-builder
$(CONTAINER_TOOL) buildx use kmcp-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm kmcp-builder
rm Dockerfile.cross

.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > dist/install.yaml

##@ Deployment

ifndef ignore-not-found
ignore-not-found = false
endif

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -

.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
$(DOCKER_BUILDER) push ${CONTROLLER_IMG}

.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

##@ Dependencies

Expand All @@ -180,10 +205,6 @@ ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
GOLANGCI_LINT_VERSION ?= v1.63.4

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
Expand Down
3 changes: 3 additions & 0 deletions config/crd/bases/kagent.dev_mcpservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ spec:
description: HTTPTransport defines the configuration for a Streamable
HTTP transport.
properties:
path:
description: the target path where MCP is served
type: string
targetPort:
description: target port is the HTTP port that serves the MCP
server.over HTTP
Expand Down
16 changes: 0 additions & 16 deletions config/crd/kustomization.yaml

This file was deleted.

Loading
Loading