🚀 ToolHive v0.21.0 is live!
This release removes deprecated CRD fields ahead of v1beta1 API promotion, adds Cedar role-based authorization support, introduces new registry API endpoints, and fixes several bugs including OTLP endpoint path encoding and operator reconcile loops.
⚠️ Breaking Changes
- Inline
telemetryfield removed from MCPServer and MCPRemoteProxy — manifests usingspec.telemetrymust migrate totelemetryConfigRefwith an MCPTelemetryConfig resource (migration guide) - Inline
oidcConfigfield removed from MCPServer and MCPRemoteProxy — manifests usingspec.oidcConfigmust migrate tooidcConfigRefwith an MCPOIDCConfig resource (migration guide) - Inline
incomingAuth.oidcConfigremoved from VirtualMCPServer — manifests usingspec.incomingAuth.oidcConfigmust migrate tooidcConfigRef(migration guide) config.groupReffallback andexternal_auth_config_refenum removed — VirtualMCPServer now requiresspec.groupRefand the snake_case enum value is gone (migration guide)thv group runno longer supports registry-based groups — usethv group createandthv run --groupinstead (migration guide)
Migration guide: Inline telemetry field removal
Affects any MCPServer, MCPRemoteProxy, or VirtualMCPServer manifest using the inline spec.telemetry block. The TelemetryConfig and OpenTelemetryConfig CRD types are also removed.
Before
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPServer
metadata:
name: my-server
spec:
telemetry:
openTelemetry:
enabled: true
endpoint: "http://otel-collector:4318"
serviceName: "my-server"After
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPTelemetryConfig
metadata:
name: my-telemetry
spec:
openTelemetry:
enabled: true
endpoint: "http://otel-collector:4318"
---
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPServer
metadata:
name: my-server
spec:
telemetryConfigRef:
name: my-telemetry
serviceName: "my-server"Migration steps
- Create an
MCPTelemetryConfigresource with your existing telemetry settings - Replace
spec.telemetrywithspec.telemetryConfigRef.namepointing to the new resource - Apply both resources — the MCPTelemetryConfig can be shared across multiple servers
Migration guide: Inline oidcConfig removal (MCPServer / MCPRemoteProxy)
Affects any MCPServer or MCPRemoteProxy manifest using the inline spec.oidcConfig field.
Before
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPServer
metadata:
name: my-server
spec:
oidcConfig:
type: kubernetes
kubernetes:
issuer: "https://idp.example.com"
audience: "my-audience"After
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPOIDCConfig
metadata:
name: my-oidc
spec:
type: kubernetesServiceAccount
kubernetesServiceAccount:
issuer: "https://idp.example.com"
---
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPServer
metadata:
name: my-server
spec:
oidcConfigRef:
name: my-oidc
audience: "my-audience"Migration steps
- Create an
MCPOIDCConfigresource with your existing OIDC settings - Replace
spec.oidcConfigwithspec.oidcConfigRef.namepointing to the new resource - Apply both resources — the MCPOIDCConfig can be shared across multiple servers
Migration guide: Inline oidcConfig removal (VirtualMCPServer)
Affects any VirtualMCPServer manifest using spec.incomingAuth.oidcConfig.
Before
apiVersion: toolhive.stacklok.com/v1alpha1
kind: VirtualMCPServer
metadata:
name: my-vmcp
spec:
incomingAuth:
type: oidc
oidcConfig:
type: kubernetes
kubernetes:
issuer: "https://idp.example.com"
audience: "my-audience"After
apiVersion: toolhive.stacklok.com/v1alpha1
kind: MCPOIDCConfig
metadata:
name: my-oidc
spec:
type: kubernetesServiceAccount
kubernetesServiceAccount:
issuer: "https://idp.example.com"
---
apiVersion: toolhive.stacklok.com/v1alpha1
kind: VirtualMCPServer
metadata:
name: my-vmcp
spec:
incomingAuth:
type: oidc
oidcConfigRef:
name: my-oidc
audience: "my-audience"Migration steps
- Create an
MCPOIDCConfigresource with your existing OIDC settings - Replace
spec.incomingAuth.oidcConfigwithspec.incomingAuth.oidcConfigRef.name - Apply both resources
Migration guide: config.groupRef fallback and enum removal
Affects VirtualMCPServer manifests that relied on spec.config.group as a fallback (instead of spec.groupRef) or used the snake_case external_auth_config_ref enum value.
Before
apiVersion: toolhive.stacklok.com/v1alpha1
kind: VirtualMCPServer
metadata:
name: my-vmcp
spec:
config:
group: "my-group"
outgoingAuth:
backends:
- type: external_auth_config_ref
name: my-authAfter
apiVersion: toolhive.stacklok.com/v1alpha1
kind: VirtualMCPServer
metadata:
name: my-vmcp
spec:
groupRef:
name: my-group
outgoingAuth:
backends:
- type: externalAuthConfigRef
name: my-authMigration steps
- Move
spec.config.grouptospec.groupRef.name(now required) - Replace
external_auth_config_refwithexternalAuthConfigRefinoutgoingAuth.backends[*].type - Apply the updated manifest
Migration guide: Registry-based group deployment removed
Affects users running thv group run to deploy server groups defined in registry JSON files.
Before
thv group run my-registry-groupAfter
thv group create my-group
thv run --group my-group server1
thv run --group my-group server2Migration steps
- Create a runtime group with
thv group create <name> - Run each server individually with
thv run --group <name> <server> - Runtime groups (
thv group create/list/rm) and the groups API are unaffected
🆕 New Features
- Cedar authorizer now supports a
RoleClaimNamefield for extracting IdP roles (e.g. Entra IDrolesclaim) separately from group claims (#4847) - New
oidcConfigRef.resourceUrlfield lets users specify the public URL for OAuth protected resource metadata when servers are exposed via Ingress (#4855) - New
GET /api/v1beta/skills/contentendpoint retrieves SKILL.md content from OCI, git, and registry sources without installing the skill (#4810) - New v0.1 server browse endpoints (
GET /registry/{name}/v0.1/serversandGET /registry/{name}/v0.1/servers/{serverName}/versions/latest) matching upstream MCP registry spec (#4871) - Cedar authorizer now stores
serverNameto scope policies per-MCP-server, enabling rules likeresource in MCP::"<server>"(#4861) - Introduce Starlark script engine package (
pkg/script/) as the foundation for vMCP code mode — internal only, not yet wired to the server (#4748)
🐛 Bug Fixes
- OTLP endpoint URLs with custom paths (Langfuse, LangSmith) no longer get URL-encoded slashes, fixing trace export to these backends (#4815)
- Fix VirtualMCPServer reconcile loop (~10 updates/sec) caused by non-deterministic env var ordering with 4+ MCPExternalAuthConfigs (#4783)
- OIDC discovery failure no longer blocks the local key provider in embedded auth server scenarios (#4774)
thv registry loginno longer re-prompts the browser OAuth flow after the user has already authenticated (#4893)- Skills API
?limit=Nwhere N > 200 now correctly clamps to 200 instead of silently falling back to 50 (#4802) ValidatingCache.Geton an expired entry now returns the freshly loaded value instead of(zero, false), eliminating unnecessary retries (#4798)- Restored vMCP session metadata is now persisted to Redis, preventing stale per-backend session IDs in cross-pod scenarios (#4842)
- Fix BackendReconciler field index registration order —
SetupIndexesis now called beforeSetupWithManagerto prevent watch predicates from failing silently (#4724)
🧹 Misc
- Remove orphaned
OIDCConfigReftype,OIDCConfigurableinterface, and related resolver code (dead code after inline oidcConfig removal) (#4846) - Remove
UpsertfromDataStorageinterface — had zero production callers after prior migration to explicitCreate/Update(#4797) - Remove stale OpenShift values overlay from Helm chart (#4817)
- Add horizontal scaling integration and e2e tests for Redis-backed vMCP session sharing (#4724)
- Add integration test for default audience without resource parameter (#4818)
- Fix flaky port reuse test by allocating a free port at runtime instead of hardcoding 9090 (#4812)
- Fix lint issues with mcpgroup (#4838)
- Change
UpdateConfigcallback signature to return error for future validation support (#4845, #4858) - Enforce go.mod patch version check in Taskfile and CI (#4864)
- Add color annotations to Claude Code agent definitions (#4853)
- Add
/release-notesskill for automated release note generation (#4852)
📦 Dependencies
| Module | Version |
|---|---|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp |
1.43.0 |
github.com/stacklok/toolhive-catalog |
v0.20260416.0 |
Full commit log
What's Changed
- Remove stale OpenShift values overlay from Helm chart by @ChrisJBurns in #4817
- Introduce script engine package for vMCP code mode by @jerm-dro in #4748
- Allow local key provider to bypass OIDC discovery failure by @jhrozek in #4774
- Fix port reuse test using hardcoded port number by @blkt in #4812
- Bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.41.0 to 1.43.0 by @dependabot[bot] in #4687
- Address review findings from v0.1 skills OpenAPI PR by @samuv in #4802
- Add integration test for default audience without resource parameter by @jhrozek in #4818
- Remove deprecated inline telemetry field from CRDs by @ChrisJBurns in #4819
- Remove deprecated inline oidcConfig from MCPServer and MCPRemoteProxy by @ChrisJBurns in #4820
- Add horizontal scaling tests for vmcp by @yrobla in #4724
- Remove Upsert from DataStorage interface — closes #4726 by @yrobla in #4797
- fix lint issues with mcpgroup by @yrobla in #4838
- Add GetContent API for on-the-fly SKILL.md retrieval from OCI and git sources by @samuv in #4810
- Remove deprecated incomingAuth.oidcConfig from VirtualMCPServer by @ChrisJBurns in #4822
- Remove config.groupRef fallback and external_auth_config_ref enum by @ChrisJBurns in #4834
- Remove orphaned OIDCConfigRef type and OIDCConfigurable interface by @ChrisJBurns in #4846
- Add color annotations to agent definitions by @ChrisJBurns in #4853
- Add RoleClaimName to Cedar ConfigOptions by @jhrozek in #4847
- Return error from
UpdateConfigcallbacks by @blkt in #4845 - Split OTLP endpoint path to fix Langfuse/LangSmith integration by @ChrisJBurns in #4815
- Simplify
UpdateConfigerror path and add test by @blkt in #4858 - Add resourceUrl field to MCPOIDCConfigReference by @ChrisJBurns in #4855
- Add release-notes skill for generating release notes by @ChrisJBurns in #4852
- Update module github.com/stacklok/toolhive-catalog to v0.20260415.0 by @renovate[bot] in #4839
- Expand singleflight boundary in ValidatingCache.Get to cover full hit+check and miss+load path by @yrobla in #4798
- Update module github.com/stacklok/toolhive-catalog to v0.20260416.0 by @renovate[bot] in #4876
- Persist restored session metadata to Redis in loadSession by @yrobla in #4842
- Enforce go.mod patch version check in Taskfile and CI by @reyortiz3 in #4864
- Drop registry-based group support by @rdimitrov in #4873
- Use scoped secrets provider for registry auth by @eleftherias in #4893
- Add v0.1 server browse endpoints by @rdimitrov in #4871
- Fix reconcile loop caused by non-deterministic env var ordering in di… by @lujunsan in #4783
- Store serverName on Cedar Authorizer by @jhrozek in #4861
- Release v0.21.0 by @stacklokbot in #4902
Full Changelog: v0.20.0...v0.21.0
🔗 Full changelog: v0.20.0...v0.21.0