Skip to content

v0.21.0

Latest

Choose a tag to compare

@stacklokbot stacklokbot released this 16 Apr 15:04
· 28 commits to main since this release
26aab50

🚀 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 telemetry field removed from MCPServer and MCPRemoteProxy — manifests using spec.telemetry must migrate to telemetryConfigRef with an MCPTelemetryConfig resource (migration guide)
  • Inline oidcConfig field removed from MCPServer and MCPRemoteProxy — manifests using spec.oidcConfig must migrate to oidcConfigRef with an MCPOIDCConfig resource (migration guide)
  • Inline incomingAuth.oidcConfig removed from VirtualMCPServer — manifests using spec.incomingAuth.oidcConfig must migrate to oidcConfigRef (migration guide)
  • config.groupRef fallback and external_auth_config_ref enum removed — VirtualMCPServer now requires spec.groupRef and the snake_case enum value is gone (migration guide)
  • thv group run no longer supports registry-based groups — use thv group create and thv run --group instead (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

  1. Create an MCPTelemetryConfig resource with your existing telemetry settings
  2. Replace spec.telemetry with spec.telemetryConfigRef.name pointing to the new resource
  3. Apply both resources — the MCPTelemetryConfig can be shared across multiple servers

PR: #4819 — Part of #4827

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

  1. Create an MCPOIDCConfig resource with your existing OIDC settings
  2. Replace spec.oidcConfig with spec.oidcConfigRef.name pointing to the new resource
  3. Apply both resources — the MCPOIDCConfig can be shared across multiple servers

PR: #4820 — Closes #4829

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

  1. Create an MCPOIDCConfig resource with your existing OIDC settings
  2. Replace spec.incomingAuth.oidcConfig with spec.incomingAuth.oidcConfigRef.name
  3. Apply both resources

PR: #4822 — Closes #4830

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-auth

After

apiVersion: toolhive.stacklok.com/v1alpha1
kind: VirtualMCPServer
metadata:
  name: my-vmcp
spec:
  groupRef:
    name: my-group
  outgoingAuth:
    backends:
      - type: externalAuthConfigRef
        name: my-auth

Migration steps

  1. Move spec.config.group to spec.groupRef.name (now required)
  2. Replace external_auth_config_ref with externalAuthConfigRef in outgoingAuth.backends[*].type
  3. Apply the updated manifest

PR: #4834 — Closes #4831

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-group

After

thv group create my-group
thv run --group my-group server1
thv run --group my-group server2

Migration steps

  1. Create a runtime group with thv group create <name>
  2. Run each server individually with thv run --group <name> <server>
  3. Runtime groups (thv group create/list/rm) and the groups API are unaffected

PR: #4873 — Fixes #4867

🆕 New Features

  • Cedar authorizer now supports a RoleClaimName field for extracting IdP roles (e.g. Entra ID roles claim) separately from group claims (#4847)
  • New oidcConfigRef.resourceUrl field lets users specify the public URL for OAuth protected resource metadata when servers are exposed via Ingress (#4855)
  • New GET /api/v1beta/skills/content endpoint 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/servers and GET /registry/{name}/v0.1/servers/{serverName}/versions/latest) matching upstream MCP registry spec (#4871)
  • Cedar authorizer now stores serverName to scope policies per-MCP-server, enabling rules like resource 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 login no longer re-prompts the browser OAuth flow after the user has already authenticated (#4893)
  • Skills API ?limit=N where N > 200 now correctly clamps to 200 instead of silently falling back to 50 (#4802)
  • ValidatingCache.Get on 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 — SetupIndexes is now called before SetupWithManager to prevent watch predicates from failing silently (#4724)

🧹 Misc

  • Remove orphaned OIDCConfigRef type, OIDCConfigurable interface, and related resolver code (dead code after inline oidcConfig removal) (#4846)
  • Remove Upsert from DataStorage interface — had zero production callers after prior migration to explicit Create/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 UpdateConfig callback 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-notes skill 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 UpdateConfig callbacks by @blkt in #4845
  • Split OTLP endpoint path to fix Langfuse/LangSmith integration by @ChrisJBurns in #4815
  • Simplify UpdateConfig error 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