Releases: stacklok/toolhive
Release list
v0.40.0
🚀 Toolhive v0.40.0 is live!
This release hardens Virtual MCP authorization end-to-end — explicit HTTP 403 denials, a unified authz gate, and complete capability pagination — while laying the groundwork for agentic auth (RFC 8693 token exchange, the MCP 2026-07-28 revision) and moving MCP protocol handling onto the official modelcontextprotocol/go-sdk. It also fixes network isolation silently breaking --network host workloads and closes an SSRF gap in upstream Dynamic Client Registration.
🆕 New Features
- The embedded authorization server gains an RFC 8693 OAuth 2.0 Token Exchange grant handler, so an agent can exchange a user's token for a delegated token carrying both the user (
sub) and the acting agent (act.sub) — the foundation for agentic delegation (not yet wired into the server) (#5822). - ToolHive's request-parsing layer now understands the upcoming stateless MCP 2026-07-28 ("Modern") revision — a revision classifier, the
Mcp-Method/Mcp-Nameheader and_metavocabulary, andserver/discover/subscriptions/listenauthz registration — dormant until later slices wire it into proxy routing, with no change to existing traffic (#5834).
🐛 Bug Fixes
- Virtual MCP now returns an explicit HTTP 403 (with a JSON-RPC error code 403 and a "denied by authorization policy" message) when a Cedar policy denies a
tools/call,resources/read, orprompts/get, instead of a misleading-32602"not found" at HTTP 200 — and records the denial asdeniedin the audit log (#5841). thv run --network hostno longer silently loses outbound connectivity: network isolation (on by default) is dropped for host/none networking with a warning, and explicitly combining--isolate-network=truewith--network hostnow fails fast with an actionable error instead of starting a broken workload (#5794).- The Virtual MCP authz gate is hardened so the gate decision, the enforced decision, and the backend forward all derive from a single argument decode, and a backend tool named
execute_tool_scriptnow fails loudly instead of being silently shadowed by the code-mode virtual tool (#5850). - Virtual MCP capability discovery now follows list pagination cursors to exhaustion, so backends advertising more than one page (>1000 tools, resources, or prompts) no longer have their extra capabilities silently dropped from routing and clients (#5851).
- Upstream Dynamic Client Registration (DCR) discovery and registration calls are now routed through a private-IP-guarded HTTP client, closing an SSRF vector (CWE-918) — safe by default and honoring the upstream's existing
allow_private_ipssetting (#5826). - Multi-upstream embedded authservers with two or more OAuth2 DCR upstreams requesting the same scopes now register a distinct client per upstream instead of silently reusing the first upstream's credentials, fixing failed or misattributed authorization (#5824).
🧹 Misc
- Migrated MCP protocol handling from
mark3labs/mcp-goto the go-sdk-backedtoolhive-core/mcpcompatcompatibility shim (a pure, atomic import swap with no call-site logic changes), moving ToolHive onto the officialmodelcontextprotocol/go-sdk. Note: the stdio bridge currently forwards only progress/message notifications, sotools/list_changedand similar notifications are dropped — dynamic-capability servers may show stale lists until clients re-list (#5729). - Resolved temp-dir symlinks in the plugin adapter tests so
task testpasses on macOS (/var→/private/var); product code is unchanged (#5849).
📦 Dependencies
| Module | Version |
|---|---|
github.com/stacklok/toolhive-core |
v0.0.29 |
github.com/stacklok/toolhive-catalog |
v0.20260716.0 |
github/codeql-action |
7188fc3 |
golang.org/x/exp/jsonrpc2 |
9ea1abe |
Full commit log
What's Changed
- Add upstream identity to DCR credential cache key by @tgrunnagle in #5824
- Update github/codeql-action digest to 7188fc3 by @renovate[bot] in #5778
- Guard upstream-DCR HTTP calls against SSRF by @tgrunnagle in #5826
- Update module github.com/stacklok/toolhive-core to v0.0.29 by @renovate[bot] in #5840
- feat: migrate from mark3labs/mcp-go to toolhive-core/mcpcompat (go-sdk) by @JAORMX in #5729
- Update module github.com/stacklok/toolhive-catalog to v0.20260716.0 by @renovate[bot] in #5843
- Return HTTP 403 for authz-denied vMCP calls (#5827) by @JAORMX in #5841
- Update golang.org/x/exp/jsonrpc2 digest to 9ea1abe by @renovate[bot] in #5780
- Reconcile network isolation with network mode by @JAORMX in #5794
- Resolve temp dirs in plugin adapter tests by @jhrozek in #5849
- Add MCP 2026-07-28 revision classification and method vocabulary by @jhrozek in #5834
- Harden vMCP authz gate: single parse source and reserved-name check by @JAORMX in #5850
- Add RFC 8693 token exchange handler to the embedded AS by @jhrozek in #5822
- Follow list pagination cursors in vMCP capability discovery by @JAORMX in #5851
- Release v0.40.0 by @toolhive-release-app[bot] in #5855
Full Changelog: v0.39.0...v0.40.0
v0.39.0
What's Changed
- Stop VirtualMCPServer hot-reconcile on cleared imagePullSecrets by @jhrozek in #5821
- Update module github.com/stacklok/toolhive-core to v0.0.28 by @renovate[bot] in #5798
- Add Bedrock compatibility flag to thv llm setup by @aponcedeleonch in #5832
- Release v0.39.0 by @toolhive-release-app[bot] in #5833
Full Changelog: v0.38.0...v0.39.0
v0.38.0
What's Changed
- Fix tool-filter terminal drain dropping error bodies by @aponcedeleonch in #5816
- Add Codex App LLM setup support by @JAORMX in #5810
- Release v0.38.0 by @toolhive-release-app[bot] in #5820
Full Changelog: v0.37.0...v0.38.0
v0.37.0
What's Changed
- Document operator phase conventions by @buyicoder in #5766
- Add runtime-stage environment variables to protocol Dockerfiles by @danbarr in #5801
- Add MCP conformance CI job for thv run proxy by @jhrozek in #5806
- Prefer context7 for MCP spec lookups, drop hardcoded version by @jhrozek in #5805
- Expose --allow-docker-gateway in workload API by @kantord in #5799
- Added spec.podTemplateSpec support to MCPRemoteProxy by @Sanskarzz in #5531
- Stop SSE filter from leaking tools/list on undecodable lines by @saivedant169 in #5304
- Validate aud and resource claims in returned ID-JAG JWT by @jhrozek in #5716
- Flush tool-filter buffer after handler returns by @aponcedeleonch in #5809
- Release v0.37.0 by @toolhive-release-app[bot] in #5811
New Contributors
- @buyicoder made their first contribution in #5766
- @saivedant169 made their first contribution in #5304
Full Changelog: v0.36.0...v0.37.0
v0.36.0
What's Changed
- Add Codex CLI direct-mode support to thv llm setup by @jerm-dro in #5789
- Use llmgateway mode constants for direct/proxy modes by @JAORMX in #5790
- Update anthropics/claude-code-action digest to f1bd27c by @renovate[bot] in #5777
- Release v0.36.0 by @toolhive-release-app[bot] in #5795
Full Changelog: v0.35.0...v0.36.0
v0.35.0
What's Changed
- Update module github.com/stacklok/toolhive-core to v0.0.27 by @renovate[bot] in #5736
- Improve documentation discoverability and cross-linking by @JAORMX in #5739
- Add ListBackends/LookupBackend to the vMCP core interface by @ChrisJBurns in #5763
- Rate limiting observability (metrics and tracing) PR A by @Sanskarzz in #5701
- Suppress GO-2026-5932 (x/crypto/openpgp deprecated-by-design, no fix available) by @JAORMX in #5781
- Allow HTTP upstream OIDC issuers for in-cluster dev environments by @ChrisJBurns in #5787
- Release v0.35.0 by @toolhive-release-app[bot] in #5788
Full Changelog: v0.34.0...v0.35.0
v0.34.0
What's Changed
- Unify token-endpoint URL validation, fix insecure-mode gap by @jhrozek in #5706
- Allow custom HTTP headers on the OpenAI embedding client by @gabrielcosi in #5704
- Sort aggregated tools by name for deterministic embedding order by @gabrielcosi in #5709
- Fix documentation link rot across the repo by @JAORMX in #5711
- Add plugin install/list/info/uninstall + MaterializationAdapter (Phase 3, THV-0077) by @JAORMX in #5685
- Make --allow-docker-gateway grant host access, not just unblock it by @eleftherias in #5707
- Support nested map claims in Cedar authorization for act claim by @jhrozek in #5713
- Document that --allow-docker-gateway ignores allowed ports by @eleftherias in #5714
- Replace opaque Step A/B labels in XAA CRD comments by @jhrozek in #5703
- Unify subject provider defaulting, hard-error xaa by @jhrozek in #5708
- Update auth and security libraries by @renovate[bot] in #5670
- Update anthropics/claude-code-action action to v1.0.165 by @renovate[bot] in #5721
- Update anthropics/claude-code-action digest to 558b1d6 by @renovate[bot] in #5718
- Update aws-sdk-go-v2 monorepo by @renovate[bot] in #5722
- Update module github.com/getsentry/sentry-go to v0.47.0 by @renovate[bot] in #5726
- Update goreleaser/goreleaser-action digest to f06c13b by @renovate[bot] in #5720
- Update github/codeql-action digest to 54f647b by @renovate[bot] in #5719
- Update module github.com/stacklok/toolhive-catalog to v0.20260706.0 by @renovate[bot] in #5728
- Filter upstream auth chain via callback hook by @tgrunnagle in #5725
- Preserve external annotations on operator Services by @blkt in #5731
- Drop unconditional ACL password guard from auth server Redis storage by @JAORMX in #5734
- Remove Amp editor extension clients by @ecgang in #5717
- Expose UpstreamFilter through authserver.New facade by @tgrunnagle in #5733
- Add Claude Desktop as an LLM gateway client by @jerm-dro in #5712
- Fix TOOLHIVE_DEV plain HTTP breaking real OCI registry pulls by @samuv in #5735
- Release v0.34.0 by @toolhive-release-app[bot] in #5737
New Contributors
Full Changelog: v0.33.0...v0.34.0
v0.33.0
What's Changed
- Configure rate limits on VirtualMCPServer PR B 2 by @Sanskarzz in #5522
- Fix stale pre-pulled image tag causing flaky E2E tests by @reyortiz3 in #5693
- Add XAA auth strategy CRD support by @jhrozek in #5691
- Update go.starlark.net digest to 529d8e8 by @renovate[bot] in #5520
- Release v0.33.0 by @toolhive-release-app[bot] in #5698
Full Changelog: v0.32.0...v0.33.0
v0.32.0
🚀 Toolhive v0.32.0 is live!
This release advances vMCP cross-application authentication — adding the XAA (Cross-Application Access) outgoing-auth strategy, the OBO strategy seam, and upstream ID-token propagation — alongside meaningful security hardening (Origin/DNS-rebind protection and a credential-passthrough fix) and a batch of operator and proxy robustness fixes.
⚠️ Breaking Changes
- Origin validation & SSE CORS hardening — ToolHive now validates the HTTP
Originheader (MCP 2025-11-25 DNS-rebind protection) and removed the insecureAccess-Control-Allow-Origin: *from the legacy SSE transport. Default local (loopback) usage is unaffected; only browser clients on a non-http://localhostorigin need action via the new--allowed-originsflag (migration guide) (#4908). - vMCP Go embedders:
server.Newsignature changed —pkg/vmcp/server.Newdropped itsdiscovery.Managerparameter (7 → 6 args) and thepkg/vmcp/discoverypackage was removed. CLI, operator, and API behavior are unchanged; only out-of-tree code importing the vMCP library must update its call (migration guide) (#5627).
Migration guide: Origin validation & SSE CORS hardening
Who is affected: Only browser-based MCP clients that make cross-origin requests to ToolHive's SSE transport from an origin that is not http://localhost:<port> / http://127.0.0.1:<port> (for example, a web app served over HTTPS or from a custom hostname). Non-browser clients (IDEs, CLIs, MCP SDK clients) do not send an Origin header and are unaffected. Loopback binds (the default 127.0.0.1) auto-derive a matching local allowlist, so default local usage continues to work. Non-loopback binds without --allowed-origins are not enforced — a warning is logged instead.
Before
# Relied on the implicit Access-Control-Allow-Origin: * wildcard
thv run --transport sse some/mcp-serverAfter
# Explicitly allow the browser origin that needs cross-origin access
thv run --transport sse --allowed-origins https://my-web-app.example.com some/mcp-server
# The same flag is available on thv proxy:
thv proxy --allowed-origins https://my-web-app.example.com ...Migration steps
- Determine whether any client reaches ToolHive's SSE endpoint cross-origin from a browser. If not, no action is needed.
- For each such origin, pass
--allowed-origins=<scheme>://<host>:<port>onthv run/thv proxy. The flag is repeatable for multiple origins; matching is exact on scheme + host + port. - Consider migrating browser clients off the legacy SSE transport to the streamable-HTTP transport.
PR: #4908
Migration guide: vMCP server.New signature change
Who is affected: Only out-of-tree Go code that imports github.com/stacklok/toolhive/pkg/vmcp/server and calls server.New directly (e.g. vMCP library embedders). All in-tree callers were updated in the same PR. There is no impact for CLI, operator, or API consumers.
Before
mgr := discovery.NewManager(agg)
srv, err := server.New(ctx, cfg, router, backendClient, mgr, backendRegistry, workflowDefs)After
// discovery.Manager is removed; capability discovery is now the core's responsibility.
srv, err := server.New(ctx, cfg, router, backendClient, backendRegistry, workflowDefs)Migration steps
- Remove the
discovery.Managerargument from yourserver.Newcall (and delete thediscovery.NewManager(...)construction). - Ensure
Config.Aggregatoris set — the core now rejects a nil aggregator. - If you set
Config.AuthzMiddleware, also setConfig.Authz; the combination withoutAuthznow returnsErrInvalidConfiginstead of silently allowing all requests.
PR: #5627
🆕 New Features
- New XAA (Cross-Application Access) outgoing auth strategy implementing the ID-JAG two-step token exchange (RFC 8693 → RFC 7523) for lazy per-backend cross-application access tokens (#5684).
- Surface upstream ID tokens through the auth middleware, consolidating upstream credential retrieval into a single bulk lookup that carries both access and ID tokens (#5682).
- Added the vMCP OBO (on-behalf-of) strategy seam — a new optional
OBOfield onBackendAuthStrategyplus strategy registration and override hook (#5624). - The vMCP optimizer can now use an OpenAI-compatible embedding client via the optional
embeddingProvider/embeddingModelconfig fields (defaults to TEI, so existing configs are unchanged) (#5633). - Added
insecureAllowHTTPtoEmbeddedAuthServerConfigso VirtualMCPServer deployers can explicitly allow anhttp://issuer for in-cluster hosts, with admission-time validation instead of a proxyrunner crash (#5671). - The operator Helm chart now prints a post-install
NOTES.txtwith verification commands, a minimal MCPServer example, and documentation links (#5656).
🐛 Bug Fixes
- vMCP now returns HTTP 401 +
WWW-Authenticate(RFC 6750) when an upstream provider token is expired and cannot be refreshed, letting clients re-authenticate instead of receiving an opaque error (#5651). - Security: the upstreamswap
customheader strategy no longer forwards the client's ToolHive JWT inAuthorizationto the backend; the upstream IdP token is still delivered in the configured custom header (#5661). MCPRemoteProxynow mounts and validates the referenced OIDC CA bundle ConfigMap, fixing silent TLS failures and surfacing aCABundleRefValidatedstatus condition (#5630).- Concurrent upstream-token refreshes are now deduplicated on a shared refresher, preventing spurious upstream logouts on IdPs with refresh-token rotation + reuse detection (#5635).
- The operator no longer perpetually reconciles MCPServers using Redis session storage with a password ref —
deploymentNeedsUpdatenow mirrors the Redis password env var (#5639). - Container-internal target ports are no longer validated against host availability, so SSE/streamable-HTTP workloads keep their registry-defined target port (#5638).
- Remote proxies now set
X-Forwarded-Prototo the upstream scheme, fixing infinite redirect loops whenMCPRemoteProxyruns behind a TLS-terminating load balancer (#5646). - Upstream-token refresh now fails closed when a rotated refresh token can't be persisted, deleting the stale row instead of stranding a poisoned token (#5636).
- A typed-nil
*Identitystored in the request context is now treated as absent, restoring vMCP fallback identity injection and preventing nil-deref panics (#5653). - VirtualMCPServer now always applies its
PodTemplateSpecstrategic merge patch, so fields likeruntimeClassName,topologySpreadConstraints, andhostNetworkare no longer silently dropped (#5641). RestoreSessionno longer fabricates a partial identity, and session restore now threads the authenticated request context, fixing cross-pod Redis failover with upstream-auth strategies (#5650).DetachedEnvVarValidatorno longer rejects optional secret env vars left blank, fixing spurious "missing required secret" errors when installing registry servers via ToolHive Studio (#5689).
🧹 Misc
- Landed Phase 2 of the plugin lifecycle epic — new
pkg/plugins/pluginsvcpackages, validation, and storage migration (no user-facing surface yet) (#5676). - Removed the now-unreachable legacy vMCP discovery seam and default router (#5627).
- Removed redundant stale-ref scans from config controller watches, relying on controller-runtime's old+new object enqueue (−648 lines) (#5626).
- Removed redundant annotation-based reconcile triggers in config controllers and added the missing
MCPToolConfigwatch (#5629). - Added unit + E2E test coverage for
--allow-docker-gatewaydeny/allow behavior (#5644). - Added E2E test infrastructure for upstreamInject identity propagation after cross-pod Redis restore, plus several embedded-auth-server in-cluster fixes (#5660).
- Expanded CONTRIBUTING guidelines with
good-first-issueandgood-tenth-issuedescriptions (#5634).
📦 Dependencies
| Module | Version |
|---|---|
github.com/stacklok/toolhive-catalog |
v0.20260629.0 |
| `ant... |
v0.31.0
What's Changed
- Fix incorrect elicitation template paths in comment by @danbarr in #5610
- Update module github.com/stacklok/toolhive-core to v0.0.26 by @renovate[bot] in #5604
- Consolidate operator envtest suite bootstrap by @ChrisJBurns in #5602
- Update core workflow actions to df4cb1c by @renovate[bot] in #5461
- Index MCPOIDCConfig referencing-workload lookups by @ChrisJBurns in #5608
- Document level-triggered operator reconciliation rules by @ChrisJBurns in #5609
- Fix codespell failure: unparseable -> unparsable by @ChrisJBurns in #5612
- Dedupe operator rules to single canonical homes by @ChrisJBurns in #5613
- Fix vMCP Deployment update loop with embedded auth server by @danbarr in #5617
- Migrate issue triage workflow to claude-code-action@v1 by @danbarr in #5620
- Allow private IPs for in-cluster OIDC and OAuth2 upstream providers by @tgrunnagle in #5618
- Remove dead legacy session-registration path by @tgrunnagle in #5622
- Add opt-in code mode decorator for vMCP by @jerm-dro in #5606
- Index referencing-workload lookups across config controllers by @ChrisJBurns in #5599
- Fix multi-upstream authorization chain flows by @lorr1 in #5590
- Remove dead session-factory aggregation and composite mirrors by @tgrunnagle in #5625
- Release v0.31.0 by @toolhive-release-app[bot] in #5628
Full Changelog: v0.30.1...v0.31.0