Skip to content

Commit f1d148d

Browse files
committed
Review tweaks
1 parent 0c820b6 commit f1d148d

File tree

8 files changed

+30
-100
lines changed

8 files changed

+30
-100
lines changed

cmd/stackrox-mcp/main.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import (
88

99
"github.com/rs/zerolog"
1010
"github.com/rs/zerolog/log"
11-
flag "github.com/spf13/pflag"
11+
"github.com/spf13/pflag"
1212

1313
"github.com/stackrox/stackrox-mcp/internal/config"
1414
"github.com/stackrox/stackrox-mcp/internal/server"
1515
"github.com/stackrox/stackrox-mcp/internal/toolsets"
16-
configtools "github.com/stackrox/stackrox-mcp/internal/toolsets/config"
17-
"github.com/stackrox/stackrox-mcp/internal/toolsets/vulnerability"
16+
toolsetConfig "github.com/stackrox/stackrox-mcp/internal/toolsets/config"
17+
toolsetVulnerability "github.com/stackrox/stackrox-mcp/internal/toolsets/vulnerability"
1818
)
1919

2020
func setupLogging() {
@@ -24,27 +24,24 @@ func setupLogging() {
2424
// getToolsets initializes and returns all available toolsets
2525
func getToolsets(cfg *config.Config) []toolsets.Toolset {
2626
return []toolsets.Toolset{
27-
configtools.NewToolset(cfg),
28-
vulnerability.NewToolset(cfg),
27+
toolsetConfig.NewToolset(cfg),
28+
toolsetVulnerability.NewToolset(cfg),
2929
}
3030
}
3131

3232
func main() {
3333
setupLogging()
3434

35-
configPath := flag.String("config", "", "Path to configuration file (optional)")
36-
flag.Parse()
35+
configPath := pflag.String("config", "", "Path to configuration file (optional)")
36+
pflag.Parse()
3737

3838
cfg, err := config.LoadConfig(*configPath)
3939
if err != nil {
4040
log.Fatal().Err(err).Msg("Failed to load configuration")
4141
}
4242
log.Info().Interface("config", cfg).Msg("Configuration loaded successfully")
4343

44-
// Create registry with all toolsets
4544
registry := toolsets.NewRegistry(cfg, getToolsets(cfg))
46-
47-
// Create MCP server
4845
srv := server.NewServer(cfg, registry)
4946

5047
// Set up context with signal handling for graceful shutdown
@@ -60,7 +57,6 @@ func main() {
6057
cancel()
6158
}()
6259

63-
// Start the server
6460
log.Info().Msg("Starting StackRox MCP server")
6561
if err := srv.Start(ctx); err != nil {
6662
log.Fatal().Err(err).Msg("Server error")

cmd/stackrox-mcp/main_test.go

Lines changed: 6 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"net/http"
77
"os"
8-
"syscall"
98
"testing"
109
"time"
1110

@@ -54,12 +53,11 @@ func TestGetToolsets(t *testing.T) {
5453
},
5554
}
5655

57-
toolsets := getToolsets(cfg)
58-
59-
require.NotNil(t, toolsets)
60-
assert.Len(t, toolsets, 2, "Should have 2 toolsets")
61-
assert.Equal(t, "config_manager", toolsets[0].GetName())
62-
assert.Equal(t, "vulnerability", toolsets[1].GetName())
56+
allToolsets := getToolsets(cfg)
57+
require.NotNil(t, allToolsets)
58+
assert.Len(t, allToolsets, 2, "Should have 2 toolsets")
59+
assert.Equal(t, "config_manager", allToolsets[0].GetName())
60+
assert.Equal(t, "vulnerability", allToolsets[1].GetName())
6361
}
6462

6563
func TestGracefulShutdown(t *testing.T) {
@@ -74,11 +72,8 @@ func TestGracefulShutdown(t *testing.T) {
7472
// Use a different port to avoid conflicts
7573
cfg.Server.Port = 9999
7674

77-
// Create registry and server
7875
registry := toolsets.NewRegistry(cfg, getToolsets(cfg))
7976
srv := server.NewServer(cfg, registry)
80-
81-
// Set up context with cancellation
8277
ctx, cancel := context.WithCancel(context.Background())
8378

8479
// Start server in goroutine
@@ -102,7 +97,7 @@ func TestGracefulShutdown(t *testing.T) {
10297
// Simulate shutdown signal by canceling context
10398
cancel()
10499

105-
// Wait for server to shut down with timeout
100+
// Wait for server to shut down
106101
select {
107102
case err := <-errChan:
108103
// Server should shut down cleanly (either nil or context.Canceled)
@@ -113,64 +108,3 @@ func TestGracefulShutdown(t *testing.T) {
113108
t.Fatal("Server did not shut down within timeout period")
114109
}
115110
}
116-
117-
func TestGracefulShutdown_WithSignal(t *testing.T) {
118-
// Set up minimal valid config
119-
assert.NoError(t, os.Setenv("STACKROX_MCP__TOOLS__VULNERABILITY__ENABLED", "true"))
120-
defer func() { assert.NoError(t, os.Unsetenv("STACKROX_MCP__TOOLS__VULNERABILITY__ENABLED")) }()
121-
122-
cfg, err := config.LoadConfig("")
123-
require.NoError(t, err)
124-
require.NotNil(t, cfg)
125-
126-
// Use a different port to avoid conflicts
127-
cfg.Server.Port = 10000
128-
129-
// Create registry and server
130-
registry := toolsets.NewRegistry(cfg, getToolsets(cfg))
131-
srv := server.NewServer(cfg, registry)
132-
133-
// Set up context with cancellation and signal handling (like in main)
134-
ctx, cancel := context.WithCancel(context.Background())
135-
defer cancel()
136-
137-
sigChan := make(chan os.Signal, 1)
138-
// Note: We use a buffered channel and manually send to avoid OS signal complications in tests
139-
140-
go func() {
141-
<-sigChan
142-
cancel()
143-
}()
144-
145-
// Start server in goroutine
146-
errChan := make(chan error, 1)
147-
go func() {
148-
errChan <- srv.Start(ctx)
149-
}()
150-
151-
// Wait for server to be ready by polling
152-
serverURL := fmt.Sprintf("http://%s:%d", cfg.Server.Address, cfg.Server.Port)
153-
err = waitForServerReady(serverURL, 3*time.Second)
154-
require.NoError(t, err, "Server should start within timeout")
155-
156-
// Establish actual HTTP connection to verify server is responding
157-
resp, err := http.Get(serverURL)
158-
if err == nil {
159-
_ = resp.Body.Close()
160-
}
161-
assert.NoError(t, err, "Should be able to establish HTTP connection to server")
162-
163-
// Simulate signal by sending to channel
164-
sigChan <- syscall.SIGTERM
165-
166-
// Wait for server to shut down with timeout
167-
select {
168-
case err := <-errChan:
169-
// Server should shut down cleanly
170-
if err != nil && err != context.Canceled {
171-
t.Errorf("Server returned unexpected error: %v", err)
172-
}
173-
case <-time.After(5 * time.Second):
174-
t.Fatal("Server did not shut down within timeout period after signal")
175-
}
176-
}

internal/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (c *Config) Validate() error {
109109
return fmt.Errorf("server.address is required")
110110
}
111111

112-
if c.Server.Port <= 0 || c.Server.Port > 65535 {
112+
if c.Server.Port < 1 || c.Server.Port > 65535 {
113113
return fmt.Errorf("server.port must be between 1 and 65535")
114114
}
115115

internal/server/server.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func NewServer(cfg *config.Config, registry *toolsets.Registry) *Server {
3232
Name: "stackrox-mcp",
3333
Version: version,
3434
},
35-
nil, // No custom ServerOptions needed for now
35+
nil,
3636
)
3737

3838
return &Server{
@@ -79,12 +79,11 @@ func (s *Server) registerTools() {
7979
func (s *Server) Start(ctx context.Context) error {
8080
s.registerTools()
8181

82-
// Create Streamable HTTP handler
8382
handler := mcp.NewStreamableHTTPHandler(
8483
func(*http.Request) *mcp.Server {
8584
return s.mcp
8685
},
87-
nil, // No custom StreamableHTTPOptions needed
86+
nil,
8887
)
8988

9089
addr := fmt.Sprintf("%s:%d", s.cfg.Server.Address, s.cfg.Server.Port)
@@ -96,7 +95,6 @@ func (s *Server) Start(ctx context.Context) error {
9695
log.Info().
9796
Str("address", s.cfg.Server.Address).
9897
Int("port", s.cfg.Server.Port).
99-
Str("url", fmt.Sprintf("http://%s", addr)).
10098
Msg("Starting MCP HTTP server")
10199

102100
// Start server in a goroutine

internal/toolsets/config/toolset_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestToolset_IsEnabled_True(t *testing.T) {
2828

2929
tools := toolset.GetTools()
3030
require.NotEmpty(t, tools, "Should return tools when enabled")
31-
assert.Len(t, tools, 1, "Should have list_clusters tool")
31+
require.Len(t, tools, 1, "Should have list_clusters tool")
3232
assert.Equal(t, "list_clusters", tools[0].GetName())
3333
}
3434

internal/toolsets/registry_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func TestRegistry_GetAllTools_OneToolsetDisabled(t *testing.T) {
136136
tools := registry.GetAllTools()
137137

138138
require.NotEmpty(t, tools)
139-
assert.Len(t, tools, 1, "Should only have tools from enabled toolset")
139+
require.Len(t, tools, 1, "Should only have tools from enabled toolset")
140140
assert.Equal(t, "enabled_tool", tools[0].Name)
141141
}
142142

@@ -180,8 +180,15 @@ func TestRegistry_GetAllTools_FiltersReadWriteTools(t *testing.T) {
180180

181181
// Should only have 2 read-only tools
182182
require.Len(t, tools, 2, "Should filter out read-write tools")
183-
assert.Equal(t, "read_only_1", tools[0].Name)
184-
assert.Equal(t, "read_only_2", tools[1].Name)
183+
184+
// Verify tools are present
185+
toolNames := make(map[string]bool)
186+
for _, tool := range tools {
187+
toolNames[tool.Name] = true
188+
}
189+
190+
assert.True(t, toolNames["read_only_1"], "Should have read-only tools")
191+
assert.True(t, toolNames["read_only_2"], "Should have read-only tools")
185192
}
186193

187194
func TestRegistry_GetToolsets(t *testing.T) {
@@ -195,12 +202,11 @@ func TestRegistry_GetToolsets(t *testing.T) {
195202
})
196203

197204
toolsetList := []toolsets.Toolset{mockToolset1, mockToolset2}
198-
199205
registry := toolsets.NewRegistry(cfg, toolsetList)
200206

201207
retrievedToolsets := registry.GetToolsets()
202208

203-
assert.Len(t, retrievedToolsets, 2)
209+
require.Len(t, retrievedToolsets, 2)
204210
assert.Contains(t, retrievedToolsets, mockToolset1)
205211
assert.Contains(t, retrievedToolsets, mockToolset2)
206212
}

internal/toolsets/toolset.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@ type Tool interface {
2121

2222
// Toolset represents a collection of related tools
2323
type Toolset interface {
24-
// GetName returns the toolset name (e.g., "config_manager", "vulnerability")
24+
// GetName returns the toolset name
2525
GetName() string
2626

2727
// IsEnabled checks if this toolset is enabled in configuration
2828
IsEnabled() bool
2929

3030
// GetTools returns available tools based on configuration
31-
// Returns empty list if:
32-
// - Toolset is not enabled
33-
// - read_only_tools=true and toolset has no read-only tools
34-
// Filtering by read_only and enabled happens internally
3531
GetTools() []Tool
3632
}

internal/toolsets/vulnerability/toolset_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestToolset_IsEnabled_True(t *testing.T) {
3737

3838
tools := toolset.GetTools()
3939
require.NotEmpty(t, tools, "Should return tools when enabled")
40-
assert.Len(t, tools, 1, "Should have list_cluster_cves tool")
40+
require.Len(t, tools, 1, "Should have list_cluster_cves tool")
4141
assert.Equal(t, "list_cluster_cves", tools[0].GetName())
4242
}
4343

0 commit comments

Comments
 (0)