proxyrunner tool-filter middleware strips SEP-2322 Modern envelope from tools/list, breaking vMCP health checks
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 82/100
Research direction
Start in pkg/mcp/tool_filter.go at NewListToolsMappingMiddleware and trace how tools/list SSE responses are buffered and re-emitted. Preserve the SEP-2322 envelope while changing only result.tools, or skip rewriting enveloped responses; done means filtered Modern responses retain resultType, _meta, ttlMs, and cacheScope.
Written by the indexing model from the issue text.
Description
Bug
With an MCPServer that has toolConfigRef set, proxyrunner's tool-filter middleware (pkg/mcp/tool_filter.go, NewListToolsMappingMiddleware) buffers and rewrites tools/list SSE responses to apply the filter. The re-emitted body drops the SEP-2322 ("Modern") envelope fields: resultType, _meta (incl. io.modelcontextprotocol/serverInfo), ttlMs, cacheScope.
Impact on vMCP
vMCP classifies the backend as Modern (server/discover answers enveloped), then sends a Modern tools/list. The backend replies enveloped, but the proxy filter strips the envelope, so vMCP receives a Legacy-shaped success body → errLegacyResponseBody ("backend returned a Legacy-shaped body (no resultType); it may have executed") → health check fails → circuit breaker opens permanently; backend stays unavailable even though it is fully functional.
Reproduced on operator+vmcp+proxyrunner v0.49.0 (also reproduced with operator/vmcp at v0.48.0, same error string). Exactly the backends with toolConfigRef fail; all unfiltered backends in the same vMCP groups are healthy.
Wire evidence
Backend direct (bypassing proxy) — enveloped, correct:
data: {"jsonrpc":"2.0","id":2,"result":{"resultType":"complete","_meta":{"io.modelcontextprotocol/serverInfo":{"name":"github-mcp-server",...}}, ... "tools":[...]}}
Via proxyrunner with toolConfigRef — envelope stripped:
data: {"jsonrpc":"2.0","id":2,"result":{"tools":[...]}}
Same backend image behind an identical proxyrunner without toolConfigRef passes through enveloped and is classified healthy.
Expected
The filter should preserve the Modern envelope fields (rewrite only result.tools), or skip rewriting when the response is enveloped.
Workaround
Drop toolConfigRef and enforce the tool set server-side (e.g. GITHUB_READ_ONLY/GITHUB_TOOLSETS, kubernetes-mcp read_only = true).
- Dominant language
- Go
- Stars
- 2.2k
- Forks
- 300
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 180
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from stacklok/toolhive
-
HttpClientBuilder.Build() ignores HTTP(S)_PROXY (auth-server OAuth/DCR calls bypass forward proxy) Openneeds-triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
authentication bug needs-triage operator
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
authentication bug cli oidc p1
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
good-tenth-issue kubernetes
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
All issues in stacklok/toolhive
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 84/100
-
enhancement needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
kind/cleanup
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
kubernetes-sigs/kueue#15947 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
sympozium-ai/sympozium#627 ·
-
priority: p3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
googleapis/librarian#7636 ·