This document provides instructions and context for AI coding agents working in the kagent-dev/tools repository.
KAgent Tools is a Go-based MCP (Model Context Protocol) server that provides Kubernetes and cloud-native management tools. It wraps CLI tools (kubectl, helm, istioctl, cilium, etc.) behind a standardized MCP interface for use by AI agents.
Architecture:
┌────────────────┐
│ MCP Client │ (AI agent or kagent runtime)
└───────┬────────┘
│ MCP Protocol (SSE / Streamable HTTP)
▼
┌────────────────┐
│ MCP Server │ cmd/main.go
│ (mcp-go) │
└───────┬────────┘
│ Registers tool providers
▼
┌───────────────────────────────────────────────┐
│ Tool Providers (pkg/) │
│ k8s │ helm │ istio │ argo │ cilium │ ... │
└───────────────────────────────────────────────┘
│ CommandBuilder (internal/commands/)
▼
┌───────────────────────────────────────────────┐
│ CLI Binaries │
│ kubectl │ helm │ istioctl │ cilium │ argoctl │
└───────────────────────────────────────────────┘
tools/
├── cmd/
│ └── main.go # MCP server entry point, tool registration
├── pkg/ # Public tool provider packages
│ ├── argo/ # Argo Rollouts tools
│ ├── cilium/ # Cilium CNI networking tools
│ ├── helm/ # Helm package management tools
│ ├── istio/ # Istio service mesh tools
│ ├── k8s/ # Kubernetes management tools
│ │ └── resources/ # K8s resource sub-packages
│ ├── kubescape/ # Security scanning tools
│ ├── prometheus/ # Prometheus query tools
│ └── utils/ # DateTime and general utilities
├── internal/ # Internal packages
│ ├── cache/ # Thread-safe TTL cache with metrics
│ ├── cmd/ # Shell command execution (with mock support)
│ ├── commands/ # CommandBuilder fluent CLI interface
│ ├── errors/ # Structured ToolError with context
│ ├── logger/ # Structured logging
│ ├── metrics/ # Prometheus metrics definitions
│ ├── security/ # Input validation (K8s names, URLs, PromQL)
│ ├── telemetry/ # OpenTelemetry tracing and HTTP middleware
│ └── version/ # Version info
├── test/
│ └── e2e/ # End-to-end tests (Kind cluster)
├── scripts/ # Build and setup scripts
│ └── kind/ # Kind cluster configuration
├── helm/ # Helm chart for deployment
├── docs/ # Documentation
├── .github/workflows/ # CI/CD pipelines
│ ├── ci.yaml # Build, test, e2e, Helm tests
│ └── tag.yaml # Release tagging
├── Makefile # Build orchestration
├── Dockerfile # Multi-stage build (multi-arch)
├── go.mod # Go 1.25.6
├── DEVELOPMENT.md # Development setup and standards
└── CONTRIBUTION.md # Contribution process
Each provider lives in pkg/ and registers MCP tools via a RegisterTools(server, readOnly) function:
| Provider | Package | Purpose |
|---|---|---|
| Kubernetes | pkg/k8s/ |
kubectl get, describe, logs, exec, scale, patch, rollouts |
| Helm | pkg/helm/ |
List, install, upgrade, uninstall releases; repo management |
| Istio | pkg/istio/ |
VirtualService, Gateway, DestinationRule; proxy diagnostics |
| Argo Rollouts | pkg/argo/ |
Rollout promotion, pause/resume, canary/blue-green |
| Cilium | pkg/cilium/ |
BGP routing, cluster connectivity checks |
| Kubescape | pkg/kubescape/ |
Image scanning, configuration compliance |
| Prometheus | pkg/prometheus/ |
PromQL instant/range queries, scrape status |
| Utils | pkg/utils/ |
DateTime formatting/parsing |
| Task | Command |
|---|---|
| Build all platforms | make build |
| Format code | make fmt |
| Lint | make lint |
| Lint with auto-fix | make lint-fix |
| Run tests with coverage | make test |
| Run tests only (no build/lint) | make test-only |
| Run E2E tests | make e2e |
| Build Docker image | make docker-build |
| Build multi-arch Docker | make docker-build-all |
| Helm chart tests | make helm-test |
| Install locally | make tools-install |
| Run MCP server locally | make run |
| Check tool version updates | make check-releases |
| Run Jaeger tracing | make otel-local |
| Show all targets | make help |
Before submitting changes, run make fmt && make lint && make test.
Each provider implements a RegisterTools function that adds MCP tool handlers to the server:
func RegisterTools(server *server.MCPServer, readOnly bool) {
server.AddTool(mcp.NewTool("tool_name", ...), handleToolName)
if !readOnly {
server.AddTool(mcp.NewTool("write_tool", ...), handleWriteTool)
}
}Handler functions are prefixed with handle (e.g., handleKubectlGetEnhanced, handleHelmList).
Use the fluent CommandBuilder interface for executing CLI commands:
result, err := commands.NewCommandBuilder("helm").
WithArgs("list").
WithNamespace("default").
Execute(ctx)Available builders: KubectlBuilder(), HelmBuilder(), IstioCtlBuilder(), CiliumBuilder(), ArgoRolloutsBuilder().
MCP handlers return (*mcp.CallToolResult, error). Always return a nil Go error and use the structured ToolError type to format errors as MCP results:
toolErr := errors.NewToolError("get_pods", "kubernetes", errors.ErrValidation).
WithSuggestion("Check that the namespace exists").
WithContext("namespace", namespace)
return toolErr.ToMCPResult(), nilNever panic in tool handlers — always return a *mcp.CallToolResult.
Always validate user inputs using the internal/security package before passing them to CLI commands:
security.ValidateK8sResourceName()— Kubernetes resource namessecurity.ValidateNamespace()— Kubernetes namespacessecurity.ValidateURL()— HTTP URLssecurity.ValidatePromQLQuery()— PromQL syntaxsecurity.ValidateCommandInput()— General input sanitization
The internal/cache package provides a thread-safe generic Cache[T] with TTL:
- Cache is automatically invalidated on write operations (apply, delete, patch, scale)
- Metrics tracked: hits, misses, evictions, size
- Do not bypass caching for read-heavy operations
- Use descriptive variable and function names throughout. Names should clearly convey purpose and intent.
- Avoid abbreviations and single-letter names (except loop counters). Use
resourceNamenotrn,kubeClientnotkc,toolResultnottr. - Function names should describe what they do:
handleKubectlGetEnhancednotdoGet,validatePromQLQuerynotcheckQ. - Handler functions: prefix with
handle. - Builder methods: prefix with
With. - Validation functions: prefix with
Validate.
- Before writing new code, search for existing utilities in
internal/that already solve the problem. - Do not duplicate logic across tool providers. Shared functionality belongs in
internal/packages:- Command execution →
internal/commands/ - Error formatting →
internal/errors/ - Input validation →
internal/security/ - Caching →
internal/cache/ - Logging →
internal/logger/
- Command execution →
- If you find duplicated code while working on a change, consolidate it as part of your PR when the scope is reasonable.
- Ginkgo v2 + Gomega for behavioral tests
- testify for assertions and mocking
- Table-driven tests for comprehensive coverage
- Minimum 80% test coverage enforced by CI
Use the mock shell executor for unit tests instead of calling real CLI tools:
mockExecutor := cmd.NewMockShellExecutor()
mockExecutor.AddResponse("kubectl get pods -n default", "NAME READY STATUS\npod1 1/1 Running", nil)
ctx := cmd.WithShellExecutor(context.Background(), mockExecutor)- Unit tests: co-located
*_test.gofiles in each package - E2E tests:
test/e2e/(requires Kind cluster) - All public functions require unit tests
The main workflow (.github/workflows/ci.yaml) runs on pushes/PRs to main:
- Multi-arch Docker build — amd64 + arm64
- Go unit tests —
go test -v -cover - E2E tests — Kind cluster-based integration tests
- Helm chart tests — Chart unit tests
Additional workflow: tag.yaml for release tagging.
The server includes built-in observability:
- OpenTelemetry tracing — gRPC, HTTP exporters, stdout
- Prometheus metrics:
kagent_tools_mcp_invocations_total— invocation count by tool/providerkagent_tools_mcp_invocations_failure_total— failure countkagent_tools_mcp_registered_tools— tool inventorykagent_tools_mcp_server_info— server metadata
- Structured logging with context via
internal/logger/
Use Conventional Commits:
<type>: <description>
[optional body]
Signed-off-by: Name <email>
Types: feat, fix, docs, refactor, test, chore, perf, ci
- Do not call CLI tools directly — use the
CommandBuilderfrominternal/commands/. - Do not skip input validation — always use
internal/security/validators. - Do not return Go errors from MCP handlers — use
ToolError.ToMCPResult()instead. - Do not duplicate logic across providers — extract to
internal/packages. - Do not bypass the cache for read operations.
- Do not add new tool providers without a corresponding
RegisterToolsfunction. - Do not commit without running
make fmt && make lint && make test.
- Create a new package under
pkg/<provider>/. - Implement tool handlers (prefix with
handle). - Implement
RegisterTools(server, readOnly)— respect thereadOnlyflag for write operations. - Register the provider in
cmd/main.goinsideregisterMCP(). - Add input validation using
internal/security/. - Use
CommandBuilderfor CLI execution. - Return errors via
ToolError.ToMCPResult(). - Write unit tests with mock shell executor (80% coverage minimum).
- Add E2E tests if the tool interacts with a cluster.
- Run
make fmt && make lint && make testbefore submitting.
- DEVELOPMENT.md — Development setup and code standards
- CONTRIBUTION.md — Contribution process and PR guidelines
- docs/quickstart.md — Quick start guide