v0.20.0
🚀 Toolhive v0.20.0 is live!
This release graduates groupRef to a typed struct across all CRDs, adds stateless streamable-HTTP proxy support, brings TelemetryConfigRef to VirtualMCPServer, and expands the skills ecosystem with 10 new client integrations.
⚠️ Breaking Changes
- GroupRef changed from bare string to typed struct — existing manifests with
groupRef: my-groupwill fail CRD validation; update togroupRef: { name: my-group }and re-apply (migration guide) protectedResourceAllowPrivateIP/jwksAllowPrivateIPfield separation — users who setjwksAllowPrivateIP: trueand relied on the (unintended) side effect of it also enabling private IPs for the protected resource endpoint must now set both fields explicitly (migration guide)
Migration guide: GroupRef
Affected resources: MCPServer, MCPRemoteProxy, MCPServerEntry, VirtualMCPServer — every user deploying these CRDs with a groupRef value.
Before
spec:
groupRef: my-groupAfter
spec:
groupRef:
name: my-groupMigration steps
- Update all YAML manifests, GitOps pipelines, and Helm values to use the new struct format.
- For VirtualMCPServer, move
spec.config.groupReftospec.groupRef(the old path still works viaResolveGroupName()but is deprecated). - Apply the new CRDs:
kubectl apply -f deploy/charts/operator-crds/files/crds/ - Delete and re-create affected resources (existing etcd objects have the old string format and will fail re-validation):
kubectl get mcpservers -A -o yaml > mcpservers-backup.yaml # Edit backup to use new format, then: kubectl delete mcpservers --all -A kubectl apply -f mcpservers-backup.yaml # Repeat for mcpremoteproxies, mcpserverentries, virtualmcpservers
Migration guide: protectedResourceAllowPrivateIP
Affected users: Those who set jwksAllowPrivateIP: true and relied on it also enabling private IPs for the protected resource endpoint (due to a converter bug).
Before
spec:
config:
incomingAuth:
oidc:
jwksAllowPrivateIP: true
# protectedResourceAllowPrivateIP was silently derived from jwksAllowPrivateIPAfter
spec:
config:
incomingAuth:
oidc:
jwksAllowPrivateIP: true
protectedResourceAllowPrivateIP: true # must be set explicitlyMigration steps
- If your protected resource endpoint is on a private IP and you had only
jwksAllowPrivateIP: true, addprotectedResourceAllowPrivateIP: trueto your OIDC config (inline, MCPOIDCConfig, or ConfigMap). - No manifest format changes are required — existing YAML is structurally valid.
- The failure mode is immediate and obvious (connection refused), not silent degradation.
PR: #4784
🔄 Deprecations
spec.config.groupRefon VirtualMCPServer deprecated in favour ofspec.groupRef(typed struct) — will be removed in a future release (#4809)spec.config.telemetryon VirtualMCPServer deprecated in favour ofspec.telemetryConfigRef, which enables Kubernetes-native secret references and per-server overrides — will be removed in a future release (#4801)
🆕 New Features
- Stateless streamable-HTTP remote server support via
--statelessflag — proxies MCP servers that only accept POST requests, returning spec-compliant 405 for GET/HEAD/DELETE (#4515) - Non-standard OAuth scope parameter support via
--remote-auth-scope-param-name— enables authentication with providers like Slack that useuser_scopeinstead ofscope(#4712) - TelemetryConfigRef for VirtualMCPServer — reference shared
MCPTelemetryConfigresources with CEL validation, config hash tracking, and CA bundle support, consistent with MCPServer and MCPRemoteProxy (#4801) - OpenAPI spec for v0.1 skills registry endpoints — browsing endpoints now documented at
/api/openapi.json(#4800) - New MCP client support: Kimi Code CLI (#4788), Factory.ai (Droid) (#4795)
- Skill-supporting clients: VS Code / VS Code Insiders (#4773), Goose / Gemini CLI / Amp (#4799), Kiro (#4803), Cline / Roo Code / Windsurf / Mistral Vibe / Trae / Antigravity (#4804)
🐛 Bug Fixes
protectedResourceAllowPrivateIPwas silently ignored on VirtualMCPServer — the field is now propagated through the OIDC resolver and converter correctly (#4784)- Skill install failure when multiple clients share the same directory — deduplication helper prevents duplicate filesystem operations (#4796)
- Health check timeout silently capped at 5s — removed redundant
context.WithTimeoutthat overrodeTOOLHIVE_HEALTH_CHECK_PING_TIMEOUT(#4791) - VirtualMCPServer rejected tokens from its own auth server when clients omitted the optional RFC 8707
resourceparameter — now defaults to the sole allowed audience (#4805)
🔒 Security
- Updated
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttpfrom v1.41.0 to v1.43.0 to address CVE-2026-39882 — OTLP HTTP exporters read full response bodies without a size cap, enabling memory exhaustion (#4683)
🧹 Misc
- Remove redundant
storage.LoadfromNotifyBackendExpired(#4779) - Add regression guard for auth context propagation through
Close()(#4781) - Add
Audienceto authserver test client fixture (#4814) - Isolate
TestParseGitReferencefrom ambient env (#4813) - Add ConfigMap content assertions to vMCP telemetry integration tests (#4807)
- Add more Claude rules (#4782)
📦 Dependencies
| Module | Version |
|---|---|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp |
v1.43.0 |
helm/helm |
v3.20.2 |
thv-registry-api image |
v1.1.1 |
👋 Welcome to our newest contributor: @gmogmzGithub 🎉
Full commit log
What's Changed
- Add Kimi Code CLI as a supported MCP client by @samuv in #4788
- Support stateless streamable-HTTP remote servers by @gkatz2 in #4515
- Remove redundant storage.Load from NotifyBackendExpired by @yrobla in #4779
- Add more claude rules by @yrobla in #4782
- Add VS Code and VS Code Insiders as skill-supporting clients by @samuv in #4773
- Fix skill install failure when multiple clients share the same directory by @samuv in #4796
- Add Factory.ai as a supported MCP client by @samuv in #4795
- Add regression guard for auth context propagation through Close() by @yrobla in #4781
- Propagate protectedResourceAllowPrivateIP through OIDC resolver and converter by @ChrisJBurns in #4784
- Clean up health check dead code and timeout by @gkatz2 in #4791
- Add Goose, Gemini CLI, and Amp as skill-supporting clients by @samuv in #4799
- Add OpenAPI annotations to v0.1 skills registry endpoints by @samuv in #4800
- Add Kiro as a skill-supporting client by @samuv in #4803
- Update module go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp to v1.43.0 [SECURITY] by @renovate[bot] in #4683
- Bump go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp from 1.41.0 to 1.43.0 by @dependabot[bot] in #4684
- Update dependency helm/helm to v3.20.2 by @renovate[bot] in #4756
- Add Cline, Roo Code, Windsurf, Mistral Vibe, Trae, and Antigravity as skill-supporting clients by @samuv in #4804
- Add TelemetryConfigRef support to VirtualMCPServer CRD by @ChrisJBurns in #4801
- Update registry API image to v1.1.1 by @rdimitrov in #4806
- Grant default
audwhenresourceis absent by @blkt in #4805 - Add
Audienceto authserver test client fixture by @blkt in #4814 - Isolate
TestParseGitReferencefrom ambient env by @blkt in #4813 - Add ConfigMap content assertions to vMCP telemetry integration tests by @ChrisJBurns in #4807
- Change GroupRef from bare string to typed MCPGroupRef struct by @ChrisJBurns in #4809
- Add --remote-auth-scope-param-name for non-standard OAuth scope parameters by @gmogmzGithub in #4712
- Release v0.20.0 by @stacklokbot in #4816
New Contributors
- @gmogmzGithub made their first contribution in #4712
Full Changelog: v0.19.0...v0.20.0
🔗 Full changelog: v0.19.0...v0.20.0