Skip to content

Commit 72ddf9f

Browse files
authored
refactor: modular flag and config registration to reduce merge conflicts (#575)
2 parents a0c81de + 340d5cc commit 72ddf9f

15 files changed

+755
-447
lines changed

internal/cmd/flags.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Package cmd provides CLI flag registration using a modular pattern.
2+
//
3+
// To add a new flag without causing merge conflicts:
4+
// 1. Create a new file (e.g., flags_myfeature.go)
5+
// 2. Define your flag variable and default at the top
6+
// 3. Create an init() function that calls RegisterFlag()
7+
//
8+
// Example (flags_myfeature.go):
9+
//
10+
// package cmd
11+
//
12+
// var myFeatureEnabled bool
13+
//
14+
// func init() {
15+
// RegisterFlag(func(cmd *cobra.Command) {
16+
// cmd.Flags().BoolVar(&myFeatureEnabled, "my-feature", false, "Enable my feature")
17+
// })
18+
// }
19+
package cmd
20+
21+
import "github.com/spf13/cobra"
22+
23+
// FlagRegistrar is a function that registers flags on a command
24+
type FlagRegistrar func(cmd *cobra.Command)
25+
26+
// flagRegistrars holds all flag registration functions
27+
var flagRegistrars []FlagRegistrar
28+
29+
// RegisterFlag adds a flag registrar to be called during init
30+
// This allows each feature to register its own flags without modifying root.go
31+
func RegisterFlag(fn FlagRegistrar) {
32+
flagRegistrars = append(flagRegistrars, fn)
33+
}
34+
35+
// registerAllFlags calls all registered flag registrars
36+
func registerAllFlags(cmd *cobra.Command) {
37+
for _, fn := range flagRegistrars {
38+
fn(cmd)
39+
}
40+
}

internal/cmd/flags_core.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cmd
2+
3+
// Core flags - these are the essential flags that rarely change.
4+
// Feature-specific flags should go in separate files (e.g., flags_difc.go).
5+
6+
import "github.com/spf13/cobra"
7+
8+
// Core flag defaults
9+
const (
10+
defaultConfigFile = ""
11+
defaultConfigStdin = false
12+
defaultListenAddr = DefaultListenIPv4 + ":" + DefaultListenPort
13+
defaultRoutedMode = false
14+
defaultUnifiedMode = false
15+
defaultEnvFile = ""
16+
)
17+
18+
// Core flag variables
19+
var (
20+
configFile string
21+
configStdin bool
22+
listenAddr string
23+
routedMode bool
24+
unifiedMode bool
25+
envFile string
26+
validateEnv bool
27+
verbosity int
28+
)
29+
30+
func init() {
31+
RegisterFlag(registerCoreFlags)
32+
}
33+
34+
func registerCoreFlags(cmd *cobra.Command) {
35+
cmd.Flags().StringVarP(&configFile, "config", "c", defaultConfigFile, "Path to config file")
36+
cmd.Flags().BoolVar(&configStdin, "config-stdin", defaultConfigStdin, "Read MCP server configuration from stdin (JSON format). When enabled, overrides --config")
37+
cmd.Flags().StringVarP(&listenAddr, "listen", "l", defaultListenAddr, "HTTP server listen address")
38+
cmd.Flags().BoolVar(&routedMode, "routed", defaultRoutedMode, "Run in routed mode (each backend at /mcp/<server>)")
39+
cmd.Flags().BoolVar(&unifiedMode, "unified", defaultUnifiedMode, "Run in unified mode (all backends at /mcp)")
40+
cmd.Flags().StringVar(&envFile, "env", defaultEnvFile, "Path to .env file to load environment variables")
41+
cmd.Flags().BoolVar(&validateEnv, "validate-env", false, "Validate execution environment (Docker, env vars) before starting")
42+
cmd.Flags().CountVarP(&verbosity, "verbose", "v", "Increase verbosity level (use -v for info, -vv for debug, -vvv for trace)")
43+
44+
// Mark mutually exclusive flags
45+
cmd.MarkFlagsMutuallyExclusive("routed", "unified")
46+
}

internal/cmd/flags_difc.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package cmd
2+
3+
// DIFC (Decentralized Information Flow Control) related flags
4+
5+
import (
6+
"os"
7+
"strings"
8+
9+
"github.com/spf13/cobra"
10+
)
11+
12+
// DIFC flag defaults
13+
const (
14+
defaultEnableDIFC = false
15+
)
16+
17+
// DIFC flag variables
18+
var (
19+
enableDIFC bool
20+
)
21+
22+
func init() {
23+
RegisterFlag(func(cmd *cobra.Command) {
24+
cmd.Flags().BoolVar(&enableDIFC, "enable-difc", getDefaultEnableDIFC(), "Enable DIFC enforcement and session requirement (requires sys___init call before tool access)")
25+
})
26+
}
27+
28+
// getDefaultEnableDIFC returns the default DIFC setting, checking MCP_GATEWAY_ENABLE_DIFC
29+
// environment variable first, then falling back to the hardcoded default (false)
30+
func getDefaultEnableDIFC() bool {
31+
if envDIFC := os.Getenv("MCP_GATEWAY_ENABLE_DIFC"); envDIFC != "" {
32+
switch strings.ToLower(envDIFC) {
33+
case "1", "true", "yes", "on":
34+
return true
35+
}
36+
}
37+
return defaultEnableDIFC
38+
}

internal/cmd/flags_launch.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cmd
2+
3+
// Launch behavior flags
4+
5+
import "github.com/spf13/cobra"
6+
7+
// Launch flag defaults
8+
const (
9+
defaultSequentialLaunch = false
10+
)
11+
12+
// Launch flag variables
13+
var (
14+
sequentialLaunch bool
15+
)
16+
17+
func init() {
18+
RegisterFlag(func(cmd *cobra.Command) {
19+
cmd.Flags().BoolVar(&sequentialLaunch, "sequential-launch", defaultSequentialLaunch, "Launch MCP servers sequentially during startup (parallel launch is default)")
20+
})
21+
}

internal/cmd/flags_logging.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cmd
2+
3+
// Logging-related flags
4+
5+
import (
6+
"os"
7+
8+
"github.com/spf13/cobra"
9+
)
10+
11+
// Logging flag defaults
12+
const (
13+
defaultLogDir = "/tmp/gh-aw/mcp-logs"
14+
defaultPayloadDir = "/tmp/jq-payloads"
15+
)
16+
17+
// Logging flag variables
18+
var (
19+
logDir string
20+
payloadDir string
21+
)
22+
23+
func init() {
24+
RegisterFlag(func(cmd *cobra.Command) {
25+
cmd.Flags().StringVar(&logDir, "log-dir", getDefaultLogDir(), "Directory for log files (falls back to stdout if directory cannot be created)")
26+
cmd.Flags().StringVar(&payloadDir, "payload-dir", getDefaultPayloadDir(), "Directory for storing large payload files (segmented by session ID)")
27+
})
28+
}
29+
30+
// getDefaultLogDir returns the default log directory, checking MCP_GATEWAY_LOG_DIR
31+
// environment variable first, then falling back to the hardcoded default
32+
func getDefaultLogDir() string {
33+
if envLogDir := os.Getenv("MCP_GATEWAY_LOG_DIR"); envLogDir != "" {
34+
return envLogDir
35+
}
36+
return defaultLogDir
37+
}
38+
39+
// getDefaultPayloadDir returns the default payload directory, checking MCP_GATEWAY_PAYLOAD_DIR
40+
// environment variable first, then falling back to the hardcoded default
41+
func getDefaultPayloadDir() string {
42+
if envPayloadDir := os.Getenv("MCP_GATEWAY_PAYLOAD_DIR"); envPayloadDir != "" {
43+
return envPayloadDir
44+
}
45+
return defaultPayloadDir
46+
}

internal/cmd/root.go

Lines changed: 7 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,18 @@ import (
2020
"github.com/spf13/cobra"
2121
)
2222

23-
// Default values for command-line flags.
23+
// Exported constants for use by other packages
2424
const (
25-
defaultConfigFile = "" // No default config file - user must explicitly specify --config or --config-stdin
26-
defaultConfigStdin = false
2725
// DefaultListenIPv4 is the default interface used by the HTTP server.
2826
DefaultListenIPv4 = "127.0.0.1"
2927
// DefaultListenPort is the default port used by the HTTP server.
30-
DefaultListenPort = "3000"
31-
defaultListenAddr = DefaultListenIPv4 + ":" + DefaultListenPort
32-
defaultRoutedMode = false
33-
defaultUnifiedMode = false
34-
defaultEnvFile = ""
35-
defaultEnableDIFC = false
36-
defaultLogDir = "/tmp/gh-aw/mcp-logs"
37-
defaultPayloadDir = "/tmp/jq-payloads"
38-
defaultSequentialLaunch = false
28+
DefaultListenPort = "3000"
3929
)
4030

31+
// Package-level variables that don't belong to a specific feature
4132
var (
42-
configFile string
43-
configStdin bool
44-
listenAddr string
45-
routedMode bool
46-
unifiedMode bool
47-
envFile string
48-
enableDIFC bool
49-
logDir string
50-
payloadDir string
51-
validateEnv bool
52-
sequentialLaunch bool
53-
verbosity int // Verbosity level: 0 (default), 1 (-v info), 2 (-vv debug), 3 (-vvv trace)
54-
debugLog = logger.New("cmd:root")
55-
version = "dev" // Default version, overridden by SetVersion
33+
debugLog = logger.New("cmd:root")
34+
version = "dev" // Default version, overridden by SetVersion
5635
)
5736

5837
var rootCmd = &cobra.Command{
@@ -70,21 +49,8 @@ func init() {
7049
// Set custom error prefix for better branding
7150
rootCmd.SetErrPrefix("MCPG Error:")
7251

73-
rootCmd.Flags().StringVarP(&configFile, "config", "c", defaultConfigFile, "Path to config file")
74-
rootCmd.Flags().BoolVar(&configStdin, "config-stdin", defaultConfigStdin, "Read MCP server configuration from stdin (JSON format). When enabled, overrides --config")
75-
rootCmd.Flags().StringVarP(&listenAddr, "listen", "l", defaultListenAddr, "HTTP server listen address")
76-
rootCmd.Flags().BoolVar(&routedMode, "routed", defaultRoutedMode, "Run in routed mode (each backend at /mcp/<server>)")
77-
rootCmd.Flags().BoolVar(&unifiedMode, "unified", defaultUnifiedMode, "Run in unified mode (all backends at /mcp)")
78-
rootCmd.Flags().StringVar(&envFile, "env", defaultEnvFile, "Path to .env file to load environment variables")
79-
rootCmd.Flags().BoolVar(&enableDIFC, "enable-difc", defaultEnableDIFC, "Enable DIFC enforcement and session requirement (requires sys___init call before tool access)")
80-
rootCmd.Flags().StringVar(&logDir, "log-dir", getDefaultLogDir(), "Directory for log files (falls back to stdout if directory cannot be created)")
81-
rootCmd.Flags().StringVar(&payloadDir, "payload-dir", getDefaultPayloadDir(), "Directory for storing large payload files (segmented by session ID)")
82-
rootCmd.Flags().BoolVar(&validateEnv, "validate-env", false, "Validate execution environment (Docker, env vars) before starting")
83-
rootCmd.Flags().BoolVar(&sequentialLaunch, "sequential-launch", defaultSequentialLaunch, "Launch MCP servers sequentially during startup (parallel launch is default)")
84-
rootCmd.Flags().CountVarP(&verbosity, "verbose", "v", "Increase verbosity level (use -v for info, -vv for debug, -vvv for trace)")
85-
86-
// Mark mutually exclusive flags
87-
rootCmd.MarkFlagsMutuallyExclusive("routed", "unified")
52+
// Register all flags from feature modules (flags_*.go files)
53+
registerAllFlags(rootCmd)
8854

8955
// Register custom flag completions
9056
registerFlagCompletions(rootCmd)
@@ -93,24 +59,6 @@ func init() {
9359
rootCmd.AddCommand(newCompletionCmd())
9460
}
9561

96-
// getDefaultLogDir returns the default log directory, checking MCP_GATEWAY_LOG_DIR
97-
// environment variable first, then falling back to the hardcoded default
98-
func getDefaultLogDir() string {
99-
if envLogDir := os.Getenv("MCP_GATEWAY_LOG_DIR"); envLogDir != "" {
100-
return envLogDir
101-
}
102-
return defaultLogDir
103-
}
104-
105-
// getDefaultPayloadDir returns the default payload directory, checking MCP_GATEWAY_PAYLOAD_DIR
106-
// environment variable first, then falling back to the hardcoded default
107-
func getDefaultPayloadDir() string {
108-
if envPayloadDir := os.Getenv("MCP_GATEWAY_PAYLOAD_DIR"); envPayloadDir != "" {
109-
return envPayloadDir
110-
}
111-
return defaultPayloadDir
112-
}
113-
11462
const (
11563
// Debug log patterns for different verbosity levels
11664
debugMainPackages = "cmd:*,server:*,launcher:*"

0 commit comments

Comments
 (0)