Skip to content

Commit af7929f

Browse files
committed
Add config
1 parent aa80098 commit af7929f

File tree

8 files changed

+500
-2
lines changed

8 files changed

+500
-2
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ linters:
1818
- exhaustruct
1919
- paralleltest
2020
- testpackage
21+
- noinlineerr
2122
issues:
2223
max-issues-per-linter: 0
2324
max-same-issues: 0

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,84 @@ make build
1919

2020
Run the server:
2121
```bash
22+
# With configuration file
23+
./stackrox-mcp --config=examples/config-read-only.yaml
24+
25+
# Or using environment variables only
26+
export STACKROX_MCP__CENTRAL__URL=central.stackrox:8443
27+
export STACKROX_MCP__TOOLS__VULNERABILITY__ENABLED=true
2228
./stackrox-mcp
2329
```
2430

31+
## Configuration
32+
33+
The StackRox MCP server supports configuration through both YAML files and environment variables. Environment variables take precedence over YAML configuration.
34+
35+
### Configuration File
36+
37+
Specify a configuration file using the `--config` flag:
38+
39+
```bash
40+
./stackrox-mcp --config=/path/to/config.yaml
41+
```
42+
43+
See [examples/config-read-only.yaml](examples/config-read-only.yaml) for a complete configuration example.
44+
45+
### Environment Variables
46+
47+
All configuration options can be set via environment variables using the naming convention:
48+
49+
```
50+
STACKROX_MCP__SECTION__KEY
51+
```
52+
53+
Note the double underscore (`__`) separator between sections and keys.
54+
55+
#### Examples
56+
57+
```bash
58+
export STACKROX_MCP__CENTRAL__URL=central.stackrox:8443
59+
export STACKROX_MCP__GLOBAL__READ_ONLY_TOOLS=true
60+
export STACKROX_MCP__TOOLS__CONFIG_MANAGER__ENABLED=true
61+
```
62+
63+
### Configuration Options
64+
65+
#### Central Configuration
66+
67+
Configuration for connecting to StackRox Central.
68+
69+
| Option | Environment Variable | Type | Required | Default | Description |
70+
|--------|---------------------|------|----------|---------|-------------|
71+
| `central.url` | `STACKROX_MCP__CENTRAL__URL` | string | Yes | central.stackrox:8443 | URL of StackRox Central instance |
72+
| `central.insecure` | `STACKROX_MCP__CENTRAL__INSECURE` | bool | No | `false` | Skip TLS certificate verification |
73+
| `central.force_http1` | `STACKROX_MCP__CENTRAL__FORCE_HTTP1` | bool | No | `false` | Force HTTP/1.1 instead of HTTP/2 |
74+
75+
#### Global Configuration
76+
77+
Global MCP server settings.
78+
79+
| Option | Environment Variable | Type | Required | Default | Description |
80+
|--------|---------------------|------|----------|---------|-------------|
81+
| `global.read_only_tools` | `STACKROX_MCP__GLOBAL__READ_ONLY_TOOLS` | bool | No | `true` | Only allow read-only tools |
82+
83+
#### Tools Configuration
84+
85+
Enable or disable individual MCP tools. At least one tool has to be enabled.
86+
87+
| Option | Environment Variable | Type | Required | Default | Description |
88+
|--------|---------------------|------|----------|---------|-------------|
89+
| `tools.vulnerability.enabled` | `STACKROX_MCP__TOOLS__VULNERABILITY__ENABLED` | bool | No | `false` | Enable vulnerability management tools |
90+
| `tools.config_manager.enabled` | `STACKROX_MCP__TOOLS__CONFIG_MANAGER__ENABLED` | bool | No | `false` | Enable configuration management tools |
91+
92+
### Configuration Precedence
93+
94+
Configuration values are loaded in the following order (later sources override earlier ones):
95+
96+
1. Default values
97+
2. YAML configuration file (if provided via `--config`)
98+
3. Environment variables (highest precedence)
99+
25100
## Development
26101

27102
For detailed development guidelines, testing standards, and contribution workflows, see [CONTRIBUTING.md](.github/CONTRIBUTING.md).

cmd/stackrox-mcp/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,28 @@
22
package main
33

44
import (
5+
"flag"
56
"log/slog"
7+
"os"
68

9+
"github.com/stackrox/stackrox-mcp/internal/config"
710
"github.com/stackrox/stackrox-mcp/internal/logging"
811
)
912

1013
func main() {
1114
logging.SetupLogging()
1215

16+
configPath := flag.String("config", "", "Path to configuration file (optional)")
17+
18+
flag.Parse()
19+
20+
cfg, err := config.LoadConfig(*configPath)
21+
if err != nil {
22+
slog.Error("Failed to load configuration", "error", err)
23+
os.Exit(1)
24+
}
25+
26+
slog.Info("Configuration loaded successfully", "config", cfg)
27+
1328
slog.Info("Starting Stackrox MCP server")
1429
}

examples/config-read-only.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# StackRox MCP Server Configuration
2+
#
3+
# This is an example configuration file for the StackRox MCP server.
4+
# Copy this file and modify it according to your environment.
5+
#
6+
# Environment Variable Mapping:
7+
# All configuration options can be overridden using environment variables.
8+
# Environment variables take precedence over YAML configuration.
9+
#
10+
# Naming convention: STACKROX_MCP__SECTION__KEY
11+
# Example:
12+
# central:
13+
# url: central.stackrox:8443
14+
#
15+
# Can be overridden with:
16+
# STACKROX_MCP__CENTRAL__URL=central.stackrox:8443
17+
18+
# Central connection configuration
19+
central:
20+
# Central URL (required, default: central.stackrox:8443)
21+
# The URL of your StackRox Central instance
22+
url: central.stackrox:8443
23+
24+
# Allow insecure TLS connection (optional, default: false)
25+
# Set to true to skip TLS certificate verification
26+
insecure: false
27+
28+
# Force HTTP1 (optional, default: false)
29+
# Force HTTP/1.1 instead of HTTP/2
30+
force_http1: false
31+
32+
# Global MCP server configuration
33+
global:
34+
# Allow only read-only MCP tools (optional, default: true)
35+
# When true, only tools that perform read operations are available
36+
# When false, both read and write tools may be available (if implemented)
37+
read_only_tools: true
38+
39+
# Configuration of MCP tools
40+
# Each tool has an enable/disable flag. At least one tool has to be enabled.
41+
tools:
42+
# Vulnerability management tools
43+
vulnerability:
44+
# Enable vulnerability management tools (optional, default: false)
45+
enabled: true
46+
47+
# Configuration management tools
48+
config_manager:
49+
# Enable configuration management tools (optional, default: false)
50+
enabled: true

go.mod

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,25 @@ module github.com/stackrox/stackrox-mcp
22

33
go 1.24
44

5-
require github.com/stretchr/testify v1.11.1
5+
require (
6+
github.com/spf13/viper v1.21.0
7+
github.com/stretchr/testify v1.11.1
8+
)
69

710
require (
811
github.com/davecgh/go-spew v1.1.1 // indirect
12+
github.com/fsnotify/fsnotify v1.9.0 // indirect
13+
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
14+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
915
github.com/pmezard/go-difflib v1.0.0 // indirect
16+
github.com/sagikazarmark/locafero v0.11.0 // indirect
17+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
18+
github.com/spf13/afero v1.15.0 // indirect
19+
github.com/spf13/cast v1.10.0 // indirect
20+
github.com/spf13/pflag v1.0.10 // indirect
21+
github.com/subosito/gotenv v1.6.0 // indirect
22+
go.yaml.in/yaml/v3 v3.0.4 // indirect
23+
golang.org/x/sys v0.29.0 // indirect
24+
golang.org/x/text v0.28.0 // indirect
1025
gopkg.in/yaml.v3 v3.0.1 // indirect
1126
)

go.sum

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,47 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
4+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
5+
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
6+
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
7+
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
8+
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
9+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
11+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
12+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
13+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
14+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
15+
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
16+
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
317
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
418
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19+
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
20+
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
21+
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
22+
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
23+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
24+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
25+
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
26+
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
27+
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
28+
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
29+
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
30+
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
31+
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
32+
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
533
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
634
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
7-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
35+
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
36+
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
37+
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
38+
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
39+
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
40+
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
41+
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
42+
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
843
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
44+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
45+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
946
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
1047
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/config/config.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Package config provides configuration handling for StackRox MCP server.
2+
package config
3+
4+
import (
5+
"errors"
6+
"fmt"
7+
"strings"
8+
9+
"github.com/spf13/viper"
10+
)
11+
12+
// Config represents the complete application configuration.
13+
type Config struct {
14+
Central CentralConfig `mapstructure:"central"`
15+
Global GlobalConfig `mapstructure:"global"`
16+
Tools ToolsConfig `mapstructure:"tools"`
17+
}
18+
19+
// CentralConfig contains StackRox Central connection configuration.
20+
type CentralConfig struct {
21+
URL string `mapstructure:"url"`
22+
Insecure bool `mapstructure:"insecure"`
23+
ForceHTTP1 bool `mapstructure:"force_http1"`
24+
}
25+
26+
// GlobalConfig contains global MCP server configuration.
27+
type GlobalConfig struct {
28+
ReadOnlyTools bool `mapstructure:"read_only_tools"`
29+
}
30+
31+
// ToolsConfig contains configuration for individual MCP tools.
32+
type ToolsConfig struct {
33+
Vulnerability ToolsetVulnerabilityConfig `mapstructure:"vulnerability"`
34+
ConfigManager ToolConfigManagerConfig `mapstructure:"config_manager"`
35+
}
36+
37+
// ToolsetVulnerabilityConfig contains configuration for vulnerability management tools.
38+
type ToolsetVulnerabilityConfig struct {
39+
Enabled bool `mapstructure:"enabled"`
40+
}
41+
42+
// ToolConfigManagerConfig contains configuration for config management tools.
43+
type ToolConfigManagerConfig struct {
44+
Enabled bool `mapstructure:"enabled"`
45+
}
46+
47+
// LoadConfig loads configuration from YAML file and environment variables.
48+
// Environment variables take precedence over YAML configuration.
49+
// Env var naming convention: STACKROX_MCP__SECTION__KEY (double underscore as separator).
50+
// configPath: optional path to YAML configuration file (can be empty).
51+
func LoadConfig(configPath string) (*Config, error) {
52+
viperInstance := viper.New()
53+
54+
setDefaults(viperInstance)
55+
56+
// Set up environment variable support.
57+
// Note: SetEnvPrefix adds a single underscore, so "STACKROX_MCP_" becomes the prefix.
58+
// We want double underscores between sections, so we use "__" in the replacer.
59+
viperInstance.SetEnvPrefix("STACKROX_MCP_")
60+
viperInstance.SetEnvKeyReplacer(strings.NewReplacer(".", "__"))
61+
viperInstance.AutomaticEnv()
62+
63+
if configPath != "" {
64+
viperInstance.SetConfigFile(configPath)
65+
66+
if err := viperInstance.ReadInConfig(); err != nil {
67+
return nil, errors.Wrap(err, "failed to read config file")
68+
}
69+
}
70+
71+
var cfg Config
72+
if err := viperInstance.Unmarshal(&cfg); err != nil {
73+
return nil, errors.Wrap(err, "failed to unmarshal config")
74+
}
75+
76+
if err := cfg.Validate(); err != nil {
77+
return nil, errors.Wrap(err, "invalid configuration")
78+
}
79+
80+
return &cfg, nil
81+
}
82+
83+
// setDefaults sets default values for configuration.
84+
func setDefaults(viper *viper.Viper) {
85+
viper.SetDefault("central.url", "central.stackrox:8443")
86+
viper.SetDefault("central.insecure", false)
87+
viper.SetDefault("central.force_http1", false)
88+
89+
viper.SetDefault("global.read_only_tools", true)
90+
91+
viper.SetDefault("tools.vulnerability.enabled", false)
92+
viper.SetDefault("tools.config_manager.enabled", false)
93+
}
94+
95+
var (
96+
errURLRequired = errors.New("central.url is required")
97+
errAtLeastOneTool = errors.New("at least one tool has to be enabled")
98+
)
99+
100+
// Validate validates the configuration.
101+
func (c *Config) Validate() error {
102+
if c.Central.URL == "" {
103+
return errURLRequired
104+
}
105+
106+
if !c.Tools.Vulnerability.Enabled && !c.Tools.ConfigManager.Enabled {
107+
return errAtLeastOneTool
108+
}
109+
110+
return nil
111+
}

0 commit comments

Comments
 (0)