Skip to content

Commit a3ddfb1

Browse files
enable toolset flag (#215)
* enable toolset flag * Implement --toolsets flag * Address PR feedback: simplify types and add tests * Add changelog * Fix variable names
1 parent 87f9bfe commit a3ddfb1

File tree

8 files changed

+680
-109
lines changed

8 files changed

+680
-109
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## Unreleased
2+
3+
FEATURES
4+
5+
* **Toolsets Flag**: Added `--toolsets` flag to selectively enable tool groups. Three toolset groups are available: `registry` (public Terraform Registry), `registry-private` (private TFE/TFC registry), and `terraform` (TFE/TFC operations). Default is `registry` only.
6+
17
## 0.3.3 (Nov 21, 2025)
28

39
IMPROVEMENTS

cmd/terraform-mcp-server/init.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/hashicorp/terraform-mcp-server/pkg/client"
1818
"github.com/hashicorp/terraform-mcp-server/pkg/resources"
1919
"github.com/hashicorp/terraform-mcp-server/pkg/tools"
20+
"github.com/hashicorp/terraform-mcp-server/pkg/toolsets"
2021
"github.com/hashicorp/terraform-mcp-server/version"
2122
"github.com/mark3labs/mcp-go/server"
2223
log "github.com/sirupsen/logrus"
@@ -37,7 +38,7 @@ var (
3738
Use: "stdio",
3839
Short: "Start stdio server",
3940
Long: `Start a server that communicates via standard input/output streams using JSON-RPC messages.`,
40-
Run: func(_ *cobra.Command, _ []string) {
41+
Run: func(cmd *cobra.Command, _ []string) {
4142
logFile, err := rootCmd.PersistentFlags().GetString("log-file")
4243
if err != nil {
4344
stdlog.Fatal("Failed to get log file:", err)
@@ -47,7 +48,9 @@ var (
4748
stdlog.Fatal("Failed to initialize logger:", err)
4849
}
4950

50-
if err := runStdioServer(logger); err != nil {
51+
enabledToolsets := getToolsetsFromCmd(cmd.Root(), logger)
52+
53+
if err := runStdioServer(logger, enabledToolsets); err != nil {
5154
stdlog.Fatal("failed to run stdio server:", err)
5255
}
5356
},
@@ -81,7 +84,9 @@ var (
8184
stdlog.Fatal("Failed to get endpoint path:", err)
8285
}
8386

84-
if err := runHTTPServer(logger, host, port, endpointPath); err != nil {
87+
enabledToolsets := getToolsetsFromCmd(cmd.Root(), logger)
88+
89+
if err := runHTTPServer(logger, host, port, endpointPath, enabledToolsets); err != nil {
8590
stdlog.Fatal("failed to run streamableHTTP server:", err)
8691
}
8792
},
@@ -104,6 +109,7 @@ func init() {
104109
cobra.OnInitialize(initConfig)
105110
rootCmd.SetVersionTemplate("{{.Short}}\n{{.Version}}\n")
106111
rootCmd.PersistentFlags().String("log-file", "", "Path to log file")
112+
rootCmd.PersistentFlags().String("toolsets", "default", toolsets.GenerateToolsetsHelp())
107113

108114
// Add StreamableHTTP command flags (avoid 'h' shorthand conflict with help)
109115
streamableHTTPCmd.Flags().String("transport-host", "127.0.0.1", "Host to bind to")
@@ -142,8 +148,8 @@ func initLogger(outPath string) (*log.Logger, error) {
142148
}
143149

144150
// registerToolsAndResources registers tools and resources with the MCP server
145-
func registerToolsAndResources(hcServer *server.MCPServer, logger *log.Logger) {
146-
tools.RegisterTools(hcServer, logger)
151+
func registerToolsAndResources(hcServer *server.MCPServer, logger *log.Logger, enabledToolsets []string) {
152+
tools.RegisterTools(hcServer, logger, enabledToolsets)
147153
resources.RegisterResources(hcServer, logger)
148154
resources.RegisterResourceTemplates(hcServer, logger)
149155
}

cmd/terraform-mcp-server/main.go

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"syscall"
1515

1616
"github.com/hashicorp/terraform-mcp-server/pkg/client"
17+
"github.com/hashicorp/terraform-mcp-server/pkg/toolsets"
1718
"github.com/hashicorp/terraform-mcp-server/version"
1819

1920
"github.com/mark3labs/mcp-go/server"
@@ -24,27 +25,27 @@ import (
2425
//go:embed instructions.md
2526
var instructions string
2627

27-
func runHTTPServer(logger *log.Logger, host string, port string, endpointPath string) error {
28+
func runHTTPServer(logger *log.Logger, host string, port string, endpointPath string, enabledToolsets []string) error {
2829
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
2930
defer stop()
3031

31-
hcServer := NewServer(version.Version, logger)
32-
registerToolsAndResources(hcServer, logger)
32+
hcServer := NewServer(version.Version, logger, enabledToolsets)
33+
registerToolsAndResources(hcServer, logger, enabledToolsets)
3334

3435
return streamableHTTPServerInit(ctx, hcServer, logger, host, port, endpointPath)
3536
}
3637

37-
func runStdioServer(logger *log.Logger) error {
38+
func runStdioServer(logger *log.Logger, enabledToolsets []string) error {
3839
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
3940
defer stop()
4041

41-
hcServer := NewServer(version.Version, logger)
42-
registerToolsAndResources(hcServer, logger)
42+
hcServer := NewServer(version.Version, logger, enabledToolsets)
43+
registerToolsAndResources(hcServer, logger, enabledToolsets)
4344

4445
return serverInit(ctx, hcServer, logger)
4546
}
4647

47-
func NewServer(version string, logger *log.Logger, opts ...server.ServerOption) *server.MCPServer {
48+
func NewServer(version string, logger *log.Logger, enabledToolsets []string, opts ...server.ServerOption) *server.MCPServer {
4849
// Create rate limiting middleware with environment-based configuration
4950
rateLimitConfig := client.LoadRateLimitConfigFromEnv()
5051
rateLimitMiddleware := client.NewRateLimitMiddleware(rateLimitConfig, logger)
@@ -80,6 +81,33 @@ func NewServer(version string, logger *log.Logger, opts ...server.ServerOption)
8081
return s
8182
}
8283

84+
// parseToolsets parses and validates the toolsets flag value
85+
func parseToolsets(toolsetsFlag string, logger *log.Logger) []string {
86+
rawToolsets := strings.Split(toolsetsFlag, ",")
87+
88+
cleaned, invalid := toolsets.CleanToolsets(rawToolsets)
89+
if len(invalid) > 0 {
90+
logger.Warnf("Invalid toolsets ignored: %v", invalid)
91+
}
92+
93+
expanded := toolsets.ExpandDefaultToolset(cleaned)
94+
95+
logger.Infof("Enabled toolsets: %v", expanded)
96+
return expanded
97+
}
98+
99+
func getToolsetsFromCmd(cmd *cobra.Command, logger *log.Logger) []string {
100+
toolsetsFlag, err := cmd.Flags().GetString("toolsets")
101+
if err != nil {
102+
toolsetsFlag, err = cmd.Root().PersistentFlags().GetString("toolsets")
103+
if err != nil {
104+
logger.Warnf("Failed to get toolsets flag, using default: %v", err)
105+
toolsetsFlag = "default"
106+
}
107+
}
108+
return parseToolsets(toolsetsFlag, logger)
109+
}
110+
83111
// runDefaultCommand handles the default behavior when no subcommand is provided
84112
func runDefaultCommand(cmd *cobra.Command, _ []string) {
85113
// Default to stdio mode when no subcommand is provided
@@ -92,7 +120,10 @@ func runDefaultCommand(cmd *cobra.Command, _ []string) {
92120
stdlog.Fatal("Failed to initialize logger:", err)
93121
}
94122

95-
if err := runStdioServer(logger); err != nil {
123+
// Get toolsets from the command that was passed in
124+
enabledToolsets := getToolsetsFromCmd(cmd, logger)
125+
126+
if err := runStdioServer(logger, enabledToolsets); err != nil {
96127
stdlog.Fatal("failed to run stdio server:", err)
97128
}
98129
}
@@ -110,7 +141,9 @@ func main() {
110141
stdlog.Fatal("Failed to initialize logger:", err)
111142
}
112143

113-
if err := runHTTPServer(logger, host, port, endpointPath); err != nil {
144+
enabledToolsets := getToolsetsFromCmd(rootCmd, logger)
145+
146+
if err := runHTTPServer(logger, host, port, endpointPath, enabledToolsets); err != nil {
114147
stdlog.Fatal("failed to run StreamableHTTP server:", err)
115148
}
116149
return

0 commit comments

Comments
 (0)