Skip to content

Commit 12741a7

Browse files
JAORMXclaude
andcommitted
Add Kubernetes export format to thv export command
Add support for exporting MCP server configurations as Kubernetes MCPServer resources with the --format flag. Users can now export their running servers to K8s manifests for deployment in Kubernetes. Changes: - Add pkg/export package with k8s.go for converting RunConfig to MCPServer CRD - Enhance thv export command with --format flag (json/k8s) - Convert all RunConfig fields to appropriate MCPServer spec fields - Handle environment variables, volumes, OIDC, authz, audit, telemetry - Sanitize names to comply with Kubernetes naming requirements - Add comprehensive unit tests for all export functionality - Add e2e tests for export command with both formats 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent b58c533 commit 12741a7

File tree

7 files changed

+1479
-9
lines changed

7 files changed

+1479
-9
lines changed

cmd/thv/app/export.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,54 @@ import (
77

88
"github.com/spf13/cobra"
99

10+
"github.com/stacklok/toolhive/pkg/export"
1011
"github.com/stacklok/toolhive/pkg/runner"
1112
)
1213

14+
var exportFormat string
15+
1316
func newExportCmd() *cobra.Command {
14-
return &cobra.Command{
17+
cmd := &cobra.Command{
1518
Use: "export <workload name> <path>",
1619
Short: "Export a workload's run configuration to a file",
1720
Long: `Export a workload's run configuration to a file for sharing or backup.
1821
1922
The exported configuration can be used with 'thv run --from-config <path>' to recreate
2023
the same workload with identical settings.
2124
25+
You can export in different formats:
26+
- json: Export as RunConfig JSON (default, can be used with 'thv run --from-config')
27+
- k8s: Export as Kubernetes MCPServer resource YAML
28+
2229
Examples:
2330
24-
# Export a workload configuration to a file
31+
# Export a workload configuration to a JSON file
2532
thv export my-server ./my-server-config.json
2633
34+
# Export as Kubernetes MCPServer resource
35+
thv export my-server ./my-server.yaml --format k8s
36+
2737
# Export to a specific directory
2838
thv export github-mcp /tmp/configs/github-config.json`,
2939
Args: cobra.ExactArgs(2),
3040
RunE: exportCmdFunc,
3141
}
42+
43+
cmd.Flags().StringVar(&exportFormat, "format", "json", "Export format: json or k8s")
44+
45+
return cmd
3246
}
3347

3448
func exportCmdFunc(cmd *cobra.Command, args []string) error {
3549
ctx := cmd.Context()
3650
workloadName := args[0]
3751
outputPath := args[1]
3852

53+
// Validate format
54+
if exportFormat != "json" && exportFormat != "k8s" {
55+
return fmt.Errorf("invalid format '%s': must be 'json' or 'k8s'", exportFormat)
56+
}
57+
3958
// Load the saved run configuration
4059
runConfig, err := runner.LoadState(ctx, workloadName)
4160
if err != nil {
@@ -56,11 +75,19 @@ func exportCmdFunc(cmd *cobra.Command, args []string) error {
5675
}
5776
defer outputFile.Close()
5877

59-
// Write the configuration to the file
60-
if err := runConfig.WriteJSON(outputFile); err != nil {
61-
return fmt.Errorf("failed to write configuration to file: %w", err)
78+
// Write the configuration based on format
79+
switch exportFormat {
80+
case "json":
81+
if err := runConfig.WriteJSON(outputFile); err != nil {
82+
return fmt.Errorf("failed to write configuration to file: %w", err)
83+
}
84+
fmt.Printf("Successfully exported run configuration for '%s' to '%s'\n", workloadName, outputPath)
85+
case "k8s":
86+
if err := export.WriteK8sManifest(runConfig, outputFile); err != nil {
87+
return fmt.Errorf("failed to write Kubernetes manifest: %w", err)
88+
}
89+
fmt.Printf("Successfully exported Kubernetes MCPServer resource for '%s' to '%s'\n", workloadName, outputPath)
6290
}
6391

64-
fmt.Printf("Successfully exported run configuration for '%s' to '%s'\n", workloadName, outputPath)
6592
return nil
6693
}

cmd/thv/app/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func newVersionCmd() *cobra.Command {
3838
// If --json is set, override the format
3939
cmd.PreRun = func(_ *cobra.Command, _ []string) {
4040
if jsonOutput {
41-
outputFormat = "json"
41+
outputFormat = FormatJSON
4242
}
4343
}
4444

docs/cli/thv_export.md

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)