Summary
--tools and --toolsets CLI flags are silently ignored when the server is started in streamable-HTTP mode via the TRANSPORT_MODE env var. The flags always fall back to their declared defaults (--toolsets="all", --tools=""), regardless of what is passed on the command line. The flags work as expected with the explicit terraform-mcp-server streamable-http … subcommand invocation — only the env-var-driven shortcut is affected.
This is a regression for anyone running the server in containers/Kubernetes/Bedrock AgentCore, where the convention is to set transport via env vars and tool filtering via flags. The server then exposes every tool (including destructive HCP Terraform writes) when only registry/read tools were requested.
Reproduction
Tested against hashicorp/terraform-mcp-server:0.5.2 (also present on main, commit 5ca056e):
docker run -d --rm \
-e TRANSPORT_MODE=streamable-http \
-e TRANSPORT_HOST=0.0.0.0 \
-e TRANSPORT_PORT=8080 \
-e MCP_SESSION_MODE=stateless \
-e TFE_TOKEN=dummy \
-p 18080:8080 \
hashicorp/terraform-mcp-server:0.5.2 \
--tools=list_workspaces,get_workspace_details
# Verify the binary received --tools correctly:
docker exec <container> ps -ef
# PID USER COMMAND
# 1 root terraform-mcp-server streamable-http --tools=list_workspaces,get_workspace_details
# tools/list returns the full 43-tool catalog instead of the requested 2:
curl -s -X POST http://localhost:18080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| grep -oE '"name":"[a-zA-Z_]+"' | sort -u | wc -l
# → 43 (including attach_policy_set_to_workspaces, create_workspace, create_run, …)
# Startup log:
# level=info msg="Starting in Streamable HTTP mode based on environment configuration"
# level=info msg="Enabled toolsets: [all]"
# (no "Enabled individual tools" line — confirming the flag was never parsed)
The same invocation without TRANSPORT_MODE (taking the cobra subcommand path) honours --tools correctly.
Root cause
cmd/terraform-mcp-server/main.go (current main, lines 286–301):
if shouldUseStreamableHTTPMode() {
logger.Info("Starting in Streamable HTTP mode based on environment configuration")
…
enabledToolsets := getToolsetsFromCmd(rootCmd, logger)
…
if err := runHTTPServer(…); err != nil { … }
return
}
// Fall back to normal CLI behavior
if err := rootCmd.Execute(); err != nil { … }
When shouldUseStreamableHTTPMode() returns true (because TRANSPORT_MODE/TRANSPORT_HOST/TRANSPORT_PORT/MCP_ENDPOINT is set), the env-var-driven fast path runs before rootCmd.Execute() is called. cobra's flag parser is therefore never invoked, so:
rootCmd.PersistentFlags().GetString("toolsets") returns the declared default "all".
rootCmd.PersistentFlags().GetString("tools") returns "".
getToolsetsFromCmd(rootCmd, logger) then takes the --toolsets="all" branch unconditionally and parseIndividualTools is never reached.
The explicit streamable-http subcommand path works because cobra's Execute() parses flags before calling the subcommand's Run.
Suggested fix
Move the env-var-driven HTTP-mode detection inside runDefaultCommand (the default Run of rootCmd), so cobra's Execute() always runs and parses persistent flags first. main() collapses to:
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
…and the streamable-HTTP-via-env branch moves to runDefaultCommand, after getToolsetsFromCmd(cmd, logger). Happy to send a PR.
Environment
terraform-mcp-server v0.5.2 (also reproducible against main at 5ca056e)
TRANSPORT_MODE=streamable-http
- Both
hashicorp/terraform-mcp-server:0.5.2 Docker image and binaries built from source
Summary
--toolsand--toolsetsCLI flags are silently ignored when the server is started in streamable-HTTP mode via theTRANSPORT_MODEenv var. The flags always fall back to their declared defaults (--toolsets="all",--tools=""), regardless of what is passed on the command line. The flags work as expected with the explicitterraform-mcp-server streamable-http …subcommand invocation — only the env-var-driven shortcut is affected.This is a regression for anyone running the server in containers/Kubernetes/Bedrock AgentCore, where the convention is to set transport via env vars and tool filtering via flags. The server then exposes every tool (including destructive HCP Terraform writes) when only registry/read tools were requested.
Reproduction
Tested against
hashicorp/terraform-mcp-server:0.5.2(also present onmain, commit 5ca056e):The same invocation without
TRANSPORT_MODE(taking the cobra subcommand path) honours--toolscorrectly.Root cause
cmd/terraform-mcp-server/main.go(currentmain, lines 286–301):When
shouldUseStreamableHTTPMode()returns true (becauseTRANSPORT_MODE/TRANSPORT_HOST/TRANSPORT_PORT/MCP_ENDPOINTis set), the env-var-driven fast path runs beforerootCmd.Execute()is called. cobra's flag parser is therefore never invoked, so:rootCmd.PersistentFlags().GetString("toolsets")returns the declared default"all".rootCmd.PersistentFlags().GetString("tools")returns"".getToolsetsFromCmd(rootCmd, logger)then takes the--toolsets="all"branch unconditionally andparseIndividualToolsis never reached.The explicit
streamable-httpsubcommand path works because cobra'sExecute()parses flags before calling the subcommand'sRun.Suggested fix
Move the env-var-driven HTTP-mode detection inside
runDefaultCommand(the default Run ofrootCmd), so cobra'sExecute()always runs and parses persistent flags first.main()collapses to:…and the streamable-HTTP-via-env branch moves to
runDefaultCommand, aftergetToolsetsFromCmd(cmd, logger). Happy to send a PR.Environment
terraform-mcp-serverv0.5.2 (also reproducible againstmainat 5ca056e)TRANSPORT_MODE=streamable-httphashicorp/terraform-mcp-server:0.5.2Docker image and binaries built from source