Fix: --tools/--toolsets ignored in streamable-HTTP env-var mode (#376)#377
Fix: --tools/--toolsets ignored in streamable-HTTP env-var mode (#376)#377sebin wants to merge 4 commits into
Conversation
When the server was launched via env vars (TRANSPORT_MODE / TRANSPORT_HOST /
TRANSPORT_PORT / MCP_ENDPOINT) instead of the explicit `streamable-http`
subcommand, main() called runHTTPServer directly without ever invoking
rootCmd.Execute(). As a result cobra never parsed os.Args[1:], so both
`--tools` and `--toolsets` always fell back to their declared defaults
(`""` and `"all"`), regardless of what the operator passed on the command
line. The HCP-Terraform toolset was silently enabled in full whenever
TFE_TOKEN was present, even when the operator asked for a smaller set.
The fix moves the env-var-driven HTTP-mode detection inside
runDefaultCommand (the default Run handler of rootCmd), so cobra's
Execute() always runs first and the persistent flags are populated before
getToolsetsFromCmd reads them. main() collapses to a plain
rootCmd.Execute(). The explicit `streamable-http` subcommand path is
unchanged.
Verified locally on linux/arm64:
TRANSPORT_MODE=streamable-http MCP_SESSION_MODE=stateless TFE_TOKEN=x \
./terraform-mcp-server --tools=list_workspaces,get_workspace_details &
curl -s -X POST http://localhost:8080/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
# Before: 43. After: 2.
All 571 existing tests pass.
Fixes hashicorp#376
|
Heads-up on a side effect of the structural change that I should have called out in the PR body — the four-line logger setup at the top of the old logFile, _ := rootCmd.PersistentFlags().GetString("log-file")
logLevel := getLogLevel(rootCmd)
logFormat := getLogFormat(rootCmd)
logger, err := initLogger(logFile, logLevel, logFormat)These reads ran before After the fix, the env-var-driven HTTP branch lives inside |
|
Hey @sebin Thanks for finding the issue and providing the fix :) |
Lock the fix in: when rootCmd.Execute() is invoked with --tools or --toolsets while TRANSPORT_MODE / TRANSPORT_PORT / TRANSPORT_HOST / MCP_ENDPOINT select streamable-HTTP, the cobra Run callback must receive a command whose flag values are populated, so getToolsetsFromCmd returns the operator's selection rather than the full default catalog. The tests stub rootCmd.Run with a capture-only callback so no server is started. resetPersistentFlag clears state between tests since rootCmd is a package-level global. Refs hashicorp#376.
Summary
Fixes #376.
When the server was launched via env vars (
TRANSPORT_MODE/TRANSPORT_HOST/TRANSPORT_PORT/MCP_ENDPOINT) instead of the explicitstreamable-httpsubcommand,main()calledrunHTTPServerdirectly without ever callingrootCmd.Execute(). cobra therefore never parsedos.Args[1:], so both--toolsand--toolsetsalways fell back to their declared defaults (""and"all"), regardless of what the operator passed on the command line. The HCP-Terraform toolset was silently enabled in full wheneverTFE_TOKENwas present, even when the operator asked for a smaller set.Change
runDefaultCommand(the defaultRunofrootCmd), so cobra'sExecute()always runs first and the--tools/--toolsetspersistent flags are populated beforegetToolsetsFromCmdreads them.main()to a plainrootCmd.Execute().Diff is +18 / -18.
Verification
```bash
TRANSPORT_MODE=streamable-http MCP_SESSION_MODE=stateless TFE_TOKEN=x \
./terraform-mcp-server --tools=list_workspaces,get_workspace_details &
curl -s -X POST http://localhost:8080/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
```
Existing test suite passes:
```
$ go test ./...
ok ... 571 passed in 10 packages
```
Test plan
Notes for reviewers
I did not add a new test because `runDefaultCommand` blocks on the server until SIGINT and the existing tests don't have a harness for that path. Happy to add one (e.g. extracting the toolset-selection block into a helper that takes a stub for the server-run function) if maintainers want it.