Skip to content

Commit 1b93c20

Browse files
committed
fix cyclomatic complexity in main
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
1 parent 3771269 commit 1b93c20

File tree

1 file changed

+96
-43
lines changed

1 file changed

+96
-43
lines changed

cmd/server/main.go

Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,32 @@ const (
2323
)
2424

2525
func main() {
26-
// Parse command line flags
26+
config := parseFlags()
27+
if config.help {
28+
showHelp()
29+
return
30+
}
31+
32+
ctx := setupContext()
33+
db := initializeDatabase(config.dbPath, config.readWrite)
34+
defer closeDatabase(db)
35+
36+
mcpServer := createMCPServer()
37+
registerToolsAndResources(mcpServer, db, config.readWrite)
38+
39+
runServer(ctx, mcpServer, config.addr, config.dbPath, config.readWrite)
40+
}
41+
42+
// Config holds the parsed command line configuration
43+
type Config struct {
44+
dbPath string
45+
addr string
46+
readWrite bool
47+
help bool
48+
}
49+
50+
// parseFlags parses command line flags and returns configuration
51+
func parseFlags() Config {
2752
dbPath := flag.String("db", defaultDB, "Path to SQLite database file")
2853
addr := flag.String("addr", getDefaultAddress(), "Address to listen on")
2954
readWrite := flag.Bool("read-write", false,
@@ -32,24 +57,31 @@ func main() {
3257

3358
flag.Parse()
3459

35-
if *help {
36-
fmt.Printf("SQLite MCP Server - A Model Context Protocol server for SQLite databases\n\n")
37-
fmt.Printf("Usage: %s [options]\n\n", os.Args[0])
38-
fmt.Printf("Options:\n")
39-
flag.PrintDefaults()
40-
fmt.Printf("\nEnvironment Variables:\n")
41-
fmt.Printf(" MCP_PORT Port to listen on (overrides -addr flag port)\n")
42-
fmt.Printf("\nExample:\n")
43-
fmt.Printf(" %s -db ./mydata.db -addr :8080\n", os.Args[0])
44-
fmt.Printf(" MCP_PORT=9000 %s -db ./mydata.db\n", os.Args[0])
45-
return
60+
return Config{
61+
dbPath: *dbPath,
62+
addr: *addr,
63+
readWrite: *readWrite,
64+
help: *help,
4665
}
66+
}
4767

48-
// Create a context that can be cancelled
68+
// showHelp displays the help message
69+
func showHelp() {
70+
fmt.Printf("SQLite MCP Server - A Model Context Protocol server for SQLite databases\n\n")
71+
fmt.Printf("Usage: %s [options]\n\n", os.Args[0])
72+
fmt.Printf("Options:\n")
73+
flag.PrintDefaults()
74+
fmt.Printf("\nEnvironment Variables:\n")
75+
fmt.Printf(" MCP_PORT Port to listen on (overrides -addr flag port)\n")
76+
fmt.Printf("\nExample:\n")
77+
fmt.Printf(" %s -db ./mydata.db -addr :8080\n", os.Args[0])
78+
fmt.Printf(" MCP_PORT=9000 %s -db ./mydata.db\n", os.Args[0])
79+
}
80+
81+
// setupContext creates a cancellable context with signal handling
82+
func setupContext() context.Context {
4983
ctx, cancel := context.WithCancel(context.Background())
50-
defer cancel()
5184

52-
// Set up signal handling
5385
sigCh := make(chan os.Signal, 1)
5486
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
5587
go func() {
@@ -58,42 +90,56 @@ func main() {
5890
cancel()
5991
}()
6092

93+
return ctx
94+
}
95+
96+
// initializeDatabase validates and initializes the database connection
97+
func initializeDatabase(dbPath string, readWrite bool) *database.DB {
6198
// Validate database file exists (skip check for in-memory databases)
62-
if *dbPath != ":memory:" {
63-
if _, err := os.Stat(*dbPath); os.IsNotExist(err) {
64-
log.Fatalf("Database file does not exist: %s", *dbPath)
99+
if dbPath != ":memory:" {
100+
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
101+
log.Fatalf("Database file does not exist: %s", dbPath)
65102
}
66103
}
67104

68105
// Initialize database connection with read-only mode detection
69-
db, err := database.New(*dbPath, !*readWrite)
106+
db, err := database.New(dbPath, !readWrite)
70107
if err != nil {
71108
log.Fatalf("Failed to connect to database: %v", err)
72109
}
73-
defer func() {
74-
if err := db.Close(); err != nil {
75-
log.Printf("Error closing database: %v", err)
76-
}
77-
}()
78110

79-
// Create MCP server with capabilities
80-
mcpServer := server.NewMCPServer(
111+
return db
112+
}
113+
114+
// closeDatabase safely closes the database connection
115+
func closeDatabase(db *database.DB) {
116+
if err := db.Close(); err != nil {
117+
log.Printf("Error closing database: %v", err)
118+
}
119+
}
120+
121+
// createMCPServer creates and configures the MCP server
122+
func createMCPServer() *server.MCPServer {
123+
return server.NewMCPServer(
81124
"sqlite-mcp",
82125
"1.0.0",
83126
server.WithToolCapabilities(false), // No tool list change notifications
84127
server.WithResourceCapabilities(false, false), // No resource subscriptions or change notifications
85128
server.WithLogging(), // Enable logging
86129
server.WithRecovery(), // Enable panic recovery
87130
)
131+
}
88132

133+
// registerToolsAndResources registers tools and resources with the MCP server
134+
func registerToolsAndResources(mcpServer *server.MCPServer, db *database.DB, readWrite bool) {
89135
// Initialize tools and resources
90136
queryTools := tools.New(db)
91137
schemaResources := resources.New(db)
92138

93139
// Register tools based on read-write mode
94140
for _, tool := range queryTools.GetTools() {
95141
// In read-only mode, skip write operations
96-
if !*readWrite && (tool.Name == "execute_statement") {
142+
if !readWrite && (tool.Name == "execute_statement") {
97143
log.Printf("Skipping write tool '%s' in read-only mode", tool.Name)
98144
continue
99145
}
@@ -109,28 +155,17 @@ func main() {
109155
for _, template := range schemaResources.GetResourceTemplates() {
110156
mcpServer.AddResourceTemplate(template, schemaResources.HandleResource)
111157
}
158+
}
112159

113-
// Create SSE server with defaults (following OSV pattern)
160+
// runServer starts the server and handles shutdown
161+
func runServer(ctx context.Context, mcpServer *server.MCPServer, addr, dbPath string, readWrite bool) {
114162
sseServer := server.NewSSEServer(mcpServer)
115163

116164
// Start server in a goroutine
117165
errChan := make(chan error, 1)
118166
go func() {
119-
mode := "read-write"
120-
if !*readWrite {
121-
mode = "read-only"
122-
}
123-
log.Printf("Starting SQLite MCP Server on %s (%s mode)", *addr, mode)
124-
log.Printf("Database: %s", *dbPath)
125-
126-
if *readWrite {
127-
log.Printf("Available tools: execute_query, execute_statement, list_tables, describe_table")
128-
} else {
129-
log.Printf("Available tools: execute_query, list_tables, describe_table")
130-
}
131-
log.Printf("Available resources: schema://tables, schema://table/{name}")
132-
133-
errChan <- sseServer.Start(*addr)
167+
logServerStart(addr, dbPath, readWrite)
168+
errChan <- sseServer.Start(addr)
134169
}()
135170

136171
// Wait for signal or error
@@ -146,6 +181,24 @@ func main() {
146181
log.Println("Server shutdown complete")
147182
}
148183

184+
// logServerStart logs server startup information
185+
func logServerStart(addr, dbPath string, readWrite bool) {
186+
mode := "read-only"
187+
if readWrite {
188+
mode = "read-write"
189+
}
190+
191+
log.Printf("Starting SQLite MCP Server on %s (%s mode)", addr, mode)
192+
log.Printf("Database: %s", dbPath)
193+
194+
if readWrite {
195+
log.Printf("Available tools: execute_query, execute_statement, list_tables, describe_table")
196+
} else {
197+
log.Printf("Available tools: execute_query, list_tables, describe_table")
198+
}
199+
log.Printf("Available resources: schema://tables, schema://table/{name}")
200+
}
201+
149202
// getDefaultAddress returns the address to listen on based on MCP_PORT environment variable.
150203
// If the environment variable is not set, returns ":8080".
151204
// If set, validates that the port is valid and returns ":<port>".

0 commit comments

Comments
 (0)