-
Notifications
You must be signed in to change notification settings - Fork 156
FIX stdio URL bug with proxyMode #2935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2935 +/- ##
=======================================
Coverage 56.36% 56.37%
=======================================
Files 323 323
Lines 31763 31777 +14
=======================================
+ Hits 17904 17915 +11
- Misses 12330 12333 +3
Partials 1529 1529 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
jhrozek
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this fix - the core approach of adding proxyMode to GenerateMCPServerURL is correct.
However, there's a bug in one of the call sites that would have been caught by testing the CLI (not just unit tests). Please make sure to test your changes end-to-end before submitting PRs - running thv run with different transport/proxyMode combinations and then thv list would have revealed the issue in WorkloadFromContainerInfo.
See inline comments for details.
| url := "" | ||
| if port > 0 { | ||
| url = transport.GenerateMCPServerURL(transportType, transport.LocalhostIPv4, port, name, "") | ||
| url = transport.GenerateMCPServerURL(transportType, "", transport.LocalhostIPv4, port, name, "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is passing an empty string for proxyMode, but the actual value from runConfig.ProxyMode isn't loaded until line 93. The URL gets generated before we know what the proxy mode is.
If you run thv run with --transport stdio --proxy-mode sse and then thv list, you'll see the URL shows /mcp instead of /sse#name.
The fix is to move the loadRunConfigFields call before the URL generation:
transportType := labels.GetTransportType(container.Labels)
tType, err := types.ParseTransportType(transportType)
if err != nil {
tType = types.TransportTypeSSE
}
// Load RunConfig first so we have proxyMode available
ctx := context.Background()
runConfig, err := loadRunConfigFields(ctx, name)
if err != nil {
return core.Workload{}, err
}
// Now we can generate the URL with the correct proxyMode
url := ""
if port > 0 {
url = transport.GenerateMCPServerURL(transportType, runConfig.ProxyMode, transport.LocalhostIPv4, port, name, "")
}| t.Run(tt.name, func(t *testing.T) { | ||
| t.Parallel() | ||
| url := GenerateMCPServerURL(tt.transportType, tt.host, tt.port, tt.containerName, tt.targetURI) | ||
| url := GenerateMCPServerURL(tt.transportType, tt.proxyMode, tt.host, tt.port, tt.containerName, tt.targetURI) // ✅ ADD proxyMode parameter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover comment from development - please remove before merging.
| url := GenerateMCPServerURL(tt.transportType, tt.proxyMode, tt.host, tt.port, tt.containerName, tt.targetURI) // ✅ ADD proxyMode parameter | |
| url := GenerateMCPServerURL(tt.transportType, tt.proxyMode, tt.host, tt.port, tt.containerName, tt.targetURI) |
| // Default to streamable-http if proxyMode is empty (matches CRD default) | ||
| effectiveProxyMode := proxyMode | ||
| if effectiveProxyMode == "" { | ||
| effectiveProxyMode = "streamable-http" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: consider using the typed constant types.ProxyModeStreamableHTTP.String() instead of the magic string. Same for "sse" on line 32. Not a blocker, but it's more consistent with the rest of the codebase.
|
Thankyou for your response, i will look into it and fix |
Problem
So deploying an MCPServer with
transport: stdioandproxyMode: streamable-http, the status URL shows incorectly returns/sseendpoint instead of/mcpExample
Expected status URL:
Actual status URL:
Root Cause
The bug is in
pkg/transport/url.goThis code is old and it shows that its treating stdio same as sse and ignoring proxyMode
So thinking logically we should assume that stdio always use SSE endpoint but stdio can use it either
proxyMode: sse→/sseendpointproxyMode: streamable-http→/mcpendpoint (default)And the controller at
cmd/thv-operator/controllers/mcpserver_controller.go:395only passesTransport, neverProxyMode:OLD CODE TOO missing proxyMode parameter
Solution
So I Added
proxyModeparameter toGenerateMCPServerURL()function:Logic:
For stdio transport: Use
proxyModeto easily determine endpointproxyMode: "streamable-http"→/mcpproxyMode: "sse"→/sse#nameproxyMode: ""(empty) → defaults to/mcp(matches CRD default)For other transports: JUST Ignore
proxyModeits behaviour doesnt change xDssetransport → always/sse#namestreamable-httptransport → always/mcpType Conversions
Added
string()conversions whereProxyModeis a typed string (was stuck on this one for whole night, was going crazy i just needed to convert ProxyMode string to function call, so proxyMode is defined as type ProxyMode string:Testing
Unit Tests (15/15 passing)
$ go test ./pkg/transport/... -v -run TestGenerateMCPServerURLKey test cases covering the bug:
/mcp/sse#name/mcp/sse#name/mcpAll 15 tests pass including targetURI path handling.
Changes
7 files changed:
pkg/transport/url.go- Added proxyMode parameter and logicpkg/transport/url_test.go- Added comprehensive test coveragecmd/thv-operator/controllers/mcpserver_controller.go- Updated call sitepkg/runner/runner.go- Updated call site with type conversionpkg/workloads/manager.go- Updated call site with type conversionpkg/workloads/types/types.go- Updated call site with empty string defaultpkg/vmcp/workloads/k8s.go- Updated call site with type conversionBuild status:
Impact
This fix ensures stdio transport respects the
proxyModesetting:/sse❌/mcp✅/sse✅/sse✅/sse❌/mcp✅/sse✅/sse✅/mcp✅/mcp✅Soooo since CRD is default for
proxyMode isstreamable-http` bug affects the default stdio configurationFixes #2920