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
7 changes: 7 additions & 0 deletions cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@ type ErrorHandling struct {

// OperationalConfig defines operational settings
type OperationalConfig struct {
// LogLevel sets the logging level for the Virtual MCP server
// Supported values: info, debug, warn, error
// +kubebuilder:validation:Enum=info;debug;warn;error
// +kubebuilder:default=info
// +optional
LogLevel string `json:"logLevel,omitempty"`

// Timeouts configures timeout settings
// +optional
Timeouts *TimeoutConfig `json:"timeouts,omitempty"`
Expand Down
17 changes: 14 additions & 3 deletions cmd/thv-operator/controllers/virtualmcpserver_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (r *VirtualMCPServerReconciler) deploymentForVirtualMCPServer(
replicas := int32(1)

// Build deployment components using helper functions
args := r.buildContainerArgsForVmcp()
args := r.buildContainerArgsForVmcp(vmcp)
volumeMounts, volumes := r.buildVolumesForVmcp(vmcp)
env := r.buildEnvVarsForVmcp(ctx, vmcp)
deploymentLabels, deploymentAnnotations := r.buildDeploymentMetadataForVmcp(ls, vmcp)
Expand Down Expand Up @@ -128,13 +128,24 @@ func (r *VirtualMCPServerReconciler) deploymentForVirtualMCPServer(
}

// buildContainerArgsForVmcp builds the container arguments for vmcp
func (*VirtualMCPServerReconciler) buildContainerArgsForVmcp() []string {
return []string{
func (*VirtualMCPServerReconciler) buildContainerArgsForVmcp(
vmcp *mcpv1alpha1.VirtualMCPServer,
) []string {
args := []string{
"serve",
"--config=/etc/vmcp-config/config.yaml",
"--host=0.0.0.0", // Listen on all interfaces for Kubernetes service routing
"--port=4483", // Standard vmcp port
}

// Add --log-level flag (defaults to info if not specified)
logLevel := "info" // default
if vmcp.Spec.Operational != nil && vmcp.Spec.Operational.LogLevel != "" {
logLevel = vmcp.Spec.Operational.LogLevel
}
args = append(args, "--log-level="+logLevel)

return args
}

// buildVolumesForVmcp builds volumes and volume mounts for vmcp
Expand Down
53 changes: 49 additions & 4 deletions cmd/thv-operator/controllers/virtualmcpserver_deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,56 @@ func TestDeploymentForVirtualMCPServer(t *testing.T) {
func TestBuildContainerArgsForVmcp(t *testing.T) {
t.Parallel()

r := &VirtualMCPServerReconciler{}
args := r.buildContainerArgsForVmcp()
tests := []struct {
name string
vmcp *mcpv1alpha1.VirtualMCPServer
wantArgs []string
}{
{
name: "without log level (defaults to info)",
vmcp: &mcpv1alpha1.VirtualMCPServer{
ObjectMeta: metav1.ObjectMeta{
Name: "test-vmcp",
Namespace: "default",
},
Spec: mcpv1alpha1.VirtualMCPServerSpec{
GroupRef: mcpv1alpha1.GroupRef{
Name: "test-group",
},
},
},
wantArgs: []string{"serve", "--config=/etc/vmcp-config/config.yaml", "--host=0.0.0.0", "--port=4483", "--log-level=info"},
},
{
name: "with log level debug",
vmcp: &mcpv1alpha1.VirtualMCPServer{
ObjectMeta: metav1.ObjectMeta{
Name: "test-vmcp",
Namespace: "default",
},
Spec: mcpv1alpha1.VirtualMCPServerSpec{
GroupRef: mcpv1alpha1.GroupRef{
Name: "test-group",
},
Operational: &mcpv1alpha1.OperationalConfig{
LogLevel: "debug",
},
},
},
wantArgs: []string{"serve", "--config=/etc/vmcp-config/config.yaml", "--host=0.0.0.0", "--port=4483", "--log-level=debug"},
},
}

assert.Contains(t, args, "serve")
assert.Contains(t, args, "--config=/etc/vmcp-config/config.yaml")
for _, tt := range tests {
tt := tt // capture range variable
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
r := &VirtualMCPServerReconciler{}
args := r.buildContainerArgsForVmcp(tt.vmcp)

assert.Equal(t, tt.wantArgs, args)
})
}
}

// TestBuildVolumesForVmcp tests volume and volume mount generation
Expand Down
2 changes: 1 addition & 1 deletion deploy/charts/operator-crds/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ apiVersion: v2
name: toolhive-operator-crds
description: A Helm chart for installing the ToolHive Operator CRDs into Kubernetes.
type: application
version: 0.0.73
version: 0.0.74
appVersion: "0.0.1"
2 changes: 1 addition & 1 deletion deploy/charts/operator-crds/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ToolHive Operator CRDs Helm Chart

![Version: 0.0.73](https://img.shields.io/badge/Version-0.0.73-informational?style=flat-square)
![Version: 0.0.74](https://img.shields.io/badge/Version-0.0.74-informational?style=flat-square)
![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)

A Helm chart for installing the ToolHive Operator CRDs into Kubernetes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,17 @@ spec:
failures before marking unhealthy
type: integer
type: object
logLevel:
default: info
description: |-
LogLevel sets the logging level for the Virtual MCP server
Supported values: info, debug, warn, error
enum:
- info
- debug
- warn
- error
type: string
timeouts:
description: Timeouts configures timeout settings
properties:
Expand Down
1 change: 1 addition & 0 deletions docs/operator/crd-api.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading