-
Notifications
You must be signed in to change notification settings - Fork 195
Description
Description
Background
The current package architecture has evolved organically as the project grew, leading to problematic coupling between core packages. Originally, toolsets directly depended on pkg/kubernetes, but as the project matured, the dependency structure became inverted in a way that creates architectural friction.
Problem Statement
The pkg/api package, which should be a foundational package containing type definitions and interfaces, has dependencies on pkg/kubernetes:
Current problematic imports in pkg/api:
pkg/api/toolsets.goimportspkg/kubernetes(asinternalk8s)pkg/api/prompts.goimportspkg/kubernetes(asinternalk8s)
Specific coupling points:
-
ToolHandlerParamsstruct (pkg/api/toolsets.go:67-72):type ToolHandlerParams struct { context.Context *internalk8s.Kubernetes // ← Direct dependency on concrete type ToolCallRequest ListOutput output.Output }
-
PromptHandlerParamsstruct (pkg/api/prompts.go:89-93):type PromptHandlerParams struct { context.Context *internalk8s.Kubernetes // ← Direct dependency on concrete type PromptCallRequest }
-
Toolset.GetTools()method (pkg/api/toolsets.go:46):GetTools(o internalk8s.Openshift) []ServerTool // ← Uses interface from pkg/kubernetes
This creates a quasi-circular dependency pattern:
pkg/api/config (leaf - only interfaces, no deps)
↑
pkg/kubernetes (imports pkg/api/config)
↑
pkg/api (imports pkg/kubernetes) ← PROBLEM: api should be a leaf package
↑
pkg/toolsets/* (imports pkg/api AND pkg/kubernetes)
Impact
-
PR feat(config): add configurable prompts support #559 (configurable prompts): Had to define TOML primitives in
pkg/configinstead of directly deserializingapi.Promptstructures because of the coupling. -
Reduced reusability: The
pkg/apipackage cannot be used independently without pulling in the entire Kubernetes client stack. -
Testing complexity: Testing API types requires setting up Kubernetes dependencies even when not needed.
-
Architectural violation: The API/types package should be a stable, dependency-free foundation that other packages build upon.
Previous Work
- PR refactor(config)!: extract config interfaces to pkg/api/config #566 started decoupling by extracting config interfaces to
pkg/api/config. This introducedAuthProvider,ClusterProvider,DeniedResourcesProvider, andExtendedProviderinterfaces, allowingpkg/kubernetesto depend on abstractions rather thanStaticConfigdirectly. - However, the reverse dependency (
pkg/api→pkg/kubernetes) remains unaddressed.
Proposed Solution
Phase 1: Extract Kubernetes Interfaces to pkg/api
Move the Openshift interface and introduce a new KubernetesClient interface in pkg/api:
// pkg/api/kubernetes.go (NEW FILE)
package api
import "context"
// Openshift provides OpenShift-specific detection capabilities
type Openshift interface {
IsOpenShift(context.Context) bool
}
// KubernetesClient defines the interface for Kubernetes operations
// that tool and prompt handlers need
type KubernetesClient interface {
// Core Kubernetes operations needed by toolsets
// (methods to be determined by analyzing actual usage in toolsets)
}Phase 2: Update Handler Params to Use Interfaces
// pkg/api/toolsets.go
type ToolHandlerParams struct {
context.Context
KubernetesClient // ← Interface instead of concrete type
ToolCallRequest
ListOutput output.Output
}
// pkg/api/prompts.go
type PromptHandlerParams struct {
context.Context
KubernetesClient // ← Interface instead of concrete type
PromptCallRequest
}Phase 3: Toolset Interface Cleanup
type Toolset interface {
GetName() string
GetDescription() string
GetTools(o Openshift) []ServerTool // ← Uses api.Openshift interface
}Phase 4: pkg/kubernetes Implements Interfaces
The pkg/kubernetes.Kubernetes struct would implement the api.KubernetesClient interface, and pkg/kubernetes.Manager would implement api.Openshift.
Target Architecture
pkg/api (leaf package - NO internal dependencies except pkg/api/config)
├── pkg/api/config (configuration interfaces)
├── Tool, ServerTool, Toolset definitions
├── Prompt, ServerPrompt definitions
├── KubernetesClient interface (NEW)
├── Openshift interface (MOVED from pkg/kubernetes)
↑
pkg/config (imports pkg/api/config)
↑
pkg/kubernetes (imports pkg/api, implements interfaces)
↑
pkg/toolsets/* (imports pkg/api, receives kubernetes via interfaces)
↑
pkg/mcp (orchestrates everything)
Acceptance Criteria
-
pkg/apihas no imports frompkg/kubernetes -
pkg/apionly depends onpkg/api/config,pkg/output, and standard library + external schema libraries - All toolsets continue to function correctly
- All prompts continue to function correctly
- No breaking changes to public API (toolset registration, MCP server initialization)
- All existing tests pass
- Configuration parsing (TOML) works directly with
api.Prompttypes
Tests
- Verify that
go list -f '{{.Imports}}' ./pkg/api/...does not includepkg/kubernetes - Existing test suite passes without modification
- Add interface compliance tests:
var _ api.KubernetesClient = (*kubernetes.Kubernetes)(nil)
Related Issues/PRs
- feat(config): add configurable prompts support #559 - feat(config): add configurable prompts support (suffered from current architecture)
- refactor(config)!: extract config interfaces to pkg/api/config #566 - refactor(config)!: extract config interfaces to pkg/api/config (partial solution)