Skip to content

Release v0.51.1 - #6704

Merged
rdimitrov merged 1 commit into
mainfrom
release/v0.51.1
Sep 22, 2026
Merged

rdimitrov merged 1 commit into
mainfrom
release/v0.51.1

Conversation

@toolhive-release-app

Copy link
Copy Markdown
Contributor

Release v0.51.1

Version Bump

patch release

Files Updated

  • VERSION
  • deploy/charts/operator-crds/Chart.yaml (path: version)
  • deploy/charts/operator-crds/Chart.yaml (path: appVersion)
  • deploy/charts/operator/Chart.yaml (path: version)
  • deploy/charts/operator/Chart.yaml (path: appVersion)
  • deploy/charts/operator/values.yaml (path: operator.image)
  • deploy/charts/operator/values.yaml (path: operator.toolhiveRunnerImage)
  • deploy/charts/operator/values.yaml (path: operator.vmcpImage)
  • Helm chart docs (via helm-docs)

Next Steps

  1. Review this PR
  2. Merge to main
  3. Release automation will handle the rest

Checklist

  • Version bump is correct
  • All CI checks pass

Release-Triggered-By: rdimitrov
@codecov

codecov Bot commented Sep 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.30%. Comparing base (226e1bd) to head (2756a00).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6704      +/-   ##
==========================================
- Coverage   79.30%   79.30%   -0.01%     
==========================================
  Files         800      800              
  Lines       80936    80936              
==========================================
- Hits        64189    64185       -4     
- Misses      16742    16746       +4     
  Partials        5        5              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rdimitrov
rdimitrov merged commit 2b299c1 into main Sep 22, 2026
43 checks passed
@rdimitrov
rdimitrov deleted the release/v0.51.1 branch September 22, 2026 19:37
@github-actions

Copy link
Copy Markdown
Contributor

📝 Generated release notes for v0.51.1

Auto-generated by the release-notes skill. Review and, if good, apply with:

gh release edit v0.51.1 --notes-file <paste-below>.md
Click to expand release notes

🚀 Toolhive v0.51.1 is live!

A security patch release that closes a cross-session response leak in the legacy HTTP+SSE proxy (GHSA-wm2j-ch74-276r). Deployments on the default streamable-http proxy mode are unaffected; if you run a stdio backend with --proxy-mode sse, read the breaking-change note below before upgrading.

⚠️ Breaking Changes

  • Legacy SSE proxy now routes every response to its originating session — one user's tool results can no longer reach another user's client, but the fail-closed routing also stops delivering notifications/progress, notifications/message and notifications/resources/updated, rejects server-initiated sampling/createMessage and elicitation/create with -32601, drops the reconnect replay queue, and answers a client-sent JSON-RPC response or a fractional request id with 400 instead of 202. Only stdio backends explicitly running proxyMode: sse are affected (migration guide).
Migration guide: legacy SSE proxy session routing

Who is affected

Only workloads that use the stdio transport together with the deprecated sse proxy mode. The streamable-http proxy mode — the default for stdio backends since --proxy-mode was introduced — is unaffected, and so is a container that itself speaks SSE (--transport sse), which is served by the transparent proxy instead.

Three ways to end up on the affected path:

  1. thv run --proxy-mode sse ... on the CLI.
  2. An MCPServer with both spec.transport: stdio and spec.proxyMode: sse.
  3. Silently — a workload created back when sse was the default keeps proxy_mode: sse in its persisted RunConfig, so thv restart stays on the legacy proxy without the flag ever being passed again.

Am I affected?

# Local: look for a workload that is BOTH stdio AND sse
thv list --format json | jq '.[] | select(.transport_type=="stdio" and .proxy_mode=="sse") | .name'

# Kubernetes
kubectl get mcpservers -A \
  -o jsonpath='{range .items[?(@.spec.transport=="stdio")]}{.metadata.name}{" "}{.spec.proxyMode}{"\n"}{end}'

No output from either means you are on the default streamable path and nothing changes for you. Note that thv status shows Proxy Mode: sse for --transport sse workloads too — the transport must be stdio for this change to apply.

What changes on the affected path

Behavior Before After
Backend response delivery Broadcast to every live SSE stream Delivered only to the session that issued the request, with the client's original id and id type restored
notifications/progress, notifications/message, notifications/resources/updated Broadcast to every client Dropped — the shared backend cannot attribute them to a session
*/list_changed notifications Forwarded as-is Broadcast to all live sessions, rebuilt from the method with params stripped
sampling/createMessage, elicitation/create from the backend Forwarded to a connected client Answered with JSON-RPC -32601 back to the backend
Backend ping Response broadcast to clients as an unsolicited result Answered by the proxy itself
Client POSTs a JSON-RPC response, or a call with a fractional id 202 Accepted 400 Bad Request
Messages received while no client was connected Replayed to the next client to connect Dropped

The first drop or rejection per method is logged at WARN naming the method, so proxy logs are the fastest way to confirm a behavior change traces to this release.

Before

apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
  name: my-server
spec:
  transport: stdio
  proxyMode: sse    # legacy proxy — affected by this change

After

apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
  name: my-server
spec:
  transport: stdio
  proxyMode: streamable-http   # or omit the field entirely to take the CRD default

Migration steps

  1. Move off the deprecated mode. CLI: drop --proxy-mode sse (or pass --proxy-mode streamable-http). Operator: set spec.proxyMode: streamable-http, or delete the field to take the CRD default, and let the reconcile roll the pod. API: omit proxy_mode on workload create.
  2. For an existing local workload, re-create it — thv restart replays the persisted proxy_mode from its RunConfig and will stay on sse:
    thv rm <name>
    thv run --proxy-mode streamable-http <image>
  3. Update client endpoints: GET /sse plus POST /messages?session_id=… becomes a single POST /mcp using the Mcp-Session-Id header.
  4. Know what switching does and does not restore. Streamable mode restores per-session notifications/progress and subscription-scoped notifications/resources/updated. It does not restore notifications/message (logging) or server-initiated sampling/elicitation — those are fail-closed on both proxies for a shared stdio backend and need a per-session backend deployment.
  5. If you must stay on --proxy-mode sse, verify your client does not POST JSON-RPC responses, uses integer or string request ids (no fractional numbers), does not depend on progress or logging notifications, and tolerates reconnecting without replay. There is no flag to restore the previous behavior — that behavior is the vulnerability.

PR: #6702 — fixes advisory GHSA-wm2j-ch74-276r

🐛 Bug Fixes

  • Closed a cross-session response leak in the legacy HTTP+SSE proxy where every backend JSON-RPC response was broadcast to all connected SSE streams, letting an authenticated user receive another user's tool results — and, because independent MCP clients reuse ordinary request-id sequences, accept another session's response as the answer to their own pending call (GHSA-wm2j-ch74-276r) (#6702).
  • Health checks on the legacy SSE proxy no longer surface the internal pinger's responses to clients as unsolicited results with unknown ids (#6702).

📦 Dependencies

Module Version
github.com/stacklok/toolhive-catalog v0.20260922.0
Full commit log

What's Changed

Full Changelog: v0.51.0...v0.51.1

🔗 Full changelog: v0.51.0...v0.51.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release size/XS Extra small PR: < 100 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant