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
44 changes: 41 additions & 3 deletions cmd/vmcp/app/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/spf13/viper"

"github.com/stacklok/toolhive/pkg/logger"
"github.com/stacklok/toolhive/pkg/vmcp/config"
)

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -120,10 +121,47 @@ This command checks:
}

logger.Infof("Validating configuration: %s", configPath)
// TODO: Validate configuration
// This will be implemented in a future PR when pkg/vmcp is added

return fmt.Errorf("validate command not yet implemented")
// Load configuration from YAML
loader := config.NewYAMLLoader(configPath)
cfg, err := loader.Load()
if err != nil {
logger.Errorf("Failed to load configuration: %v", err)
return fmt.Errorf("configuration loading failed: %w", err)
}

logger.Debugf("Configuration loaded successfully, performing validation...")

// Validate configuration
validator := config.NewValidator()
if err := validator.Validate(cfg); err != nil {
logger.Errorf("Configuration validation failed: %v", err)
return fmt.Errorf("validation failed: %w", err)
}

logger.Infof("✓ Configuration is valid")
logger.Infof(" Name: %s", cfg.Name)
logger.Infof(" Group: %s", cfg.GroupRef)
logger.Infof(" Incoming Auth: %s", cfg.IncomingAuth.Type)
logger.Infof(" Outgoing Auth: %s (source: %s)",
func() string {
if len(cfg.OutgoingAuth.Backends) > 0 {
return fmt.Sprintf("%d backends configured", len(cfg.OutgoingAuth.Backends))
}
return "default only"
}(),
cfg.OutgoingAuth.Source)
logger.Infof(" Conflict Resolution: %s", cfg.Aggregation.ConflictResolution)

if cfg.TokenCache != nil {
logger.Infof(" Token Cache: %s", cfg.TokenCache.Provider)
}

if len(cfg.CompositeTools) > 0 {
logger.Infof(" Composite Tools: %d defined", len(cfg.CompositeTools))
}

return nil
},
}
}
Expand Down
28 changes: 28 additions & 0 deletions examples/vmcp-config-invalid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Invalid Virtual MCP Server Configuration Example
# This file has intentional errors to test validation

# Missing required field: name
# name: "test-vmcp"
group: "test-group"

# Invalid auth type
incoming_auth:
type: invalid_type
oidc:
issuer: "https://keycloak.example.com"
client_id: "test-client"
client_secret_env: "TEST_SECRET"
audience: "vmcp"
scopes: ["openid"]

# Invalid source
outgoing_auth:
source: invalid_source
default:
type: pass_through

# Invalid conflict resolution strategy
aggregation:
conflict_resolution: invalid_strategy
conflict_resolution_config:
prefix_format: "{workload}_"
8 changes: 8 additions & 0 deletions pkg/vmcp/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ import (
"github.com/stacklok/toolhive/pkg/vmcp"
)

// Token cache provider types
const (
// CacheProviderMemory represents in-memory token cache provider
CacheProviderMemory = "memory"
// CacheProviderRedis represents Redis token cache provider
CacheProviderRedis = "redis"
)

// Config is the unified configuration model for Virtual MCP Server.
// This is platform-agnostic and used by both CLI and Kubernetes deployments.
//
Expand Down
Loading
Loading