Skip to content

v0.19.0

Choose a tag to compare

@stacklokbot stacklokbot released this 13 Apr 16:45
· 140 commits to main since this release
9d82ff5

πŸš€ Toolhive v0.19.0 is live!

This release introduces webhook CLI configuration, Skills API v0.1 endpoints, multi-client skill installation, and Cursor client support β€” alongside several CRD cleanup changes and enterprise config fixes. Three breaking changes require attention before upgrading.

⚠️ Breaking Changes

  • remoteURL/externalURL JSON tags renamed to camelCase β€” Existing MCPRemoteProxy and MCPServerEntry resources in etcd will silently lose their remoteUrl value after the CRD upgrade. Re-apply all affected manifests with the new field names. (migration guide)
  • Skills install API: client field replaced by clients β€” API consumers sending "client" will get silent misbehavior; CLI users of --client will get an unknown flag error. Update to "clients": [...] (API) or --clients (CLI). (migration guide)
  • enforceServers removed from MCPRegistry β€” Manifests with enforceServers will fail validation. Remove the field before upgrading. This feature was non-functional since v0.6.0, so no behavioral change. (migration guide)
Migration guide: remoteURL / externalURL rename

Who is affected: All MCPRemoteProxy and MCPServerEntry users.

Risk: This is the highest-risk change in this release. After the CRD upgrade, existing resources stored in etcd still contain the old remoteURL key. The controller deserializes this as an empty string (since the JSON tag is now remoteUrl), causing reconciliation to fail with "remoteUrl is required for remote proxy".

Before

apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPRemoteProxy
metadata:
  name: my-proxy
spec:
  remoteURL: https://mcp.example.com

After

apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPRemoteProxy
metadata:
  name: my-proxy
spec:
  remoteUrl: https://mcp.example.com

Field renames

CRD Old field New field
MCPRemoteProxy .spec remoteURL remoteUrl
MCPRemoteProxy .status externalURL externalUrl
MCPServerEntry .spec remoteURL remoteUrl

Migration steps

  1. Update the CRD manifests β€” install the new CRD definitions first.
  2. Update all MCPRemoteProxy and MCPServerEntry manifests β€” find/replace remoteURL: with remoteUrl:.
  3. Re-apply every affected resource β€” this rewrites the etcd data with the correct key. Simply waiting for reconciliation will not help; the old key is silently ignored.
  4. Update any JSONPath queries or tooling β€” e.g., kubectl get mcprp -o jsonpath='{.spec.remoteUrl}'.

PR: #4775 β€” Fixes #4581

Migration guide: Skills install API and CLI

Who is affected: Any scripts, CI pipelines, or API clients calling the skills install endpoint or using thv skills install --client.

API change

The request body client (string) field is replaced by clients (string array). The old client field is silently ignored β€” if sent alone, the server treats clients as empty and installs to all available clients.

// Before
{"client": "claude-code"}

// After
{"clients": ["claude-code"]}

CLI change

The --client flag is removed. Use --clients (accepts comma-separated values) or --all-clients.

# Before
thv skills install myskill --client claude-code

# After
thv skills install myskill --clients claude-code

# Install to all clients
thv skills install myskill --all-clients

Migration steps

  1. API consumers β€” update request bodies from "client": "..." to "clients": ["..."].
  2. CLI users β€” replace --client with --clients in all scripts and commands.
  3. Multi-client installs β€” use --clients claude-code,cursor or --all-clients to target multiple clients in one operation.

PR: #4732

Migration guide: enforceServers removal

Who is affected: MCPRegistry users with enforceServers in their manifests. Note: this feature has been silently non-functional since PR #2568 removed the backing data sources β€” no existing deployment was getting actual enforcement.

Before

apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPRegistry
metadata:
  name: my-registry
spec:
  enforceServers: true
  configYAML: |
    ...

After

apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPRegistry
metadata:
  name: my-registry
spec:
  configYAML: |
    ...

Migration steps

  1. Remove enforceServers from all MCPRegistry manifests (both in-cluster and in GitOps repos).
  2. Remove any automation or alerting that watches the ImageValidated condition β€” it will no longer appear in status.
  3. Re-apply or upgrade the CRD manifest before upgrading the operator.

PR: #4776 β€” Fixes #4717

πŸ”„ Deprecations

  • backendAuthType: external_auth_config_ref deprecated in favour of externalAuthConfigRef on VirtualMCPServer β€” the old snake_case value is still accepted but will be removed in a future release (#4563)
  • spec.telemetry (inline) on MCPRemoteProxy deprecated in favour of spec.telemetryConfigRef referencing a shared MCPTelemetryConfig resource β€” setting both is rejected by CEL validation (#4719)

πŸ†• New Features

  • thv run now supports webhook-based tool call authorization via --webhook-url, --webhook-timeout, and --webhook-failure-policy flags (#4410)
  • Two new Skills API v0.1 endpoints for browsing and fetching skills from the registry (#4753)
  • thv skills install now supports installing to multiple clients in a single command with --clients or --all-clients, with atomic rollback on failure (#4732)
  • Cursor is now recognized as a skill-supporting client (#4762)
  • MCPRemoteProxy now supports telemetryConfigRef for shared telemetry configuration, bringing it to parity with MCPServer (#4719)

πŸ› Bug Fixes

  • Proxy now returns 503 instead of 401 when OAuth tokens are expired, preventing MCP clients from entering a broken OAuth discovery loop (#4722)
  • Three gaps that allowed the non_registry_servers policy to be bypassed when running remote MCP servers by URL are now enforced (#4752)
  • Webhook 422 responses are now treated as unconditional deny regardless of failurePolicy setting (#4703)
  • runtime_config API now validates inputs at the boundary and keeps merge behavior scoped to the API layer (#4435)
  • Enterprise config provider is now consistently respected in thv run, registry routes, and HTTP handler setup (#4740, #4754, #4751, #4755)
  • ValidatingCache now supports bounded LRU capacity, preventing unbounded memory growth in long-running deployments (#4731)

🧹 Misc

  • Skills system architecture documentation added (#4758, #4759)
  • Integration tests added for authServerRef on MCPServer and MCPRemoteProxy (#4708)
  • Implementation plan section added to PR template (#4737)
  • Flaky test fixes and test stability improvements (#4739, #4745)
  • Dependency updates: toolhive-catalog v0.20260413.0, go-containerregistry v0.21.5, golang.org/x/exp/jsonrpc2 746e56f (#4666, #4757, #4750)

Full commit log

What's Changed

  • Fix runtime_config API semantics and validation by @slyt3 in #4435
  • Fix flaky TestForEachStep_ErrorAbort by @jerm-dro in #4739
  • Fix GetDefaultProvider bypassing registered config factory by @reyortiz3 in #4740
  • Add deflake skill for finding and fixing flaky tests by @jerm-dro in #4746
  • Fix stale config in registry routes and WorkloadService by @reyortiz3 in #4751
  • Enforce non-registry-server policy gate for remote URL workloads by @reyortiz3 in #4752
  • Add v0.1 skills API endpoints by @rdimitrov in #4753
  • honor webhook http 422 as unconditional deny by @Sanskarzz in #4703
  • Fix NewHandler using config.NewDefaultProvider instead of config.NewProvider by @reyortiz3 in #4754
  • Update golang.org/x/exp/jsonrpc2 digest to 746e56f by @renovate[bot] in #4750
  • Update anthropics/claude-code-action digest to b47fd72 by @renovate[bot] in #4749
  • Update module github.com/google/go-containerregistry to v0.21.5 by @renovate[bot] in #4757
  • Wait for running state before deleting in lifecycle E2E test by @jerm-dro in #4745
  • Add skills system architecture documentation by @JAORMX in #4758
  • Support multi-client and all-clients skill installation by @samuv in #4732
  • Add LRU capacity to ValidatingCache, remove sentinel pattern, add storage Update by @yrobla in #4731
  • Use cfg.NewProvider() in run flags to respect enterprise provider factory by @reyortiz3 in #4755
  • Return 503 for expired proxy tokens by @gkatz2 in #4722
  • Add Cursor as a skill-supporting client by @samuv in #4762
  • Webhook Middleware Phase 4: CLI configuration support by @Sanskarzz in #4410
  • Fix accuracy issues in skills architecture documentation by @rdimitrov in #4759
  • Update module github.com/stacklok/toolhive-catalog to v0.20260413.0 by @renovate[bot] in #4666
  • Add TelemetryConfigRef support to MCPRemoteProxy by @ChrisJBurns in #4719
  • Rename remoteURL and externalURL JSON tags to standard camelCase by @ChrisJBurns in #4775
  • Add implementation plan section to PR template by @jerm-dro in #4737
  • fix(operator): rename BackendAuthType enum value to camelCase by @tmchow in #4563
  • Add integration tests for authServerRef on MCPServer and MCPRemoteProxy by @tgrunnagle in #4708
  • Remove enforceServers and image validation from MCPRegistry by @ChrisJBurns in #4776

Full Changelog: v0.18.0...v0.19.0

πŸ”— Full changelog: v0.18.0...v0.19.0